Принципы GIT

GIT — это распределенная система контроля версий. Давайте поговорим о том, что означают слова в этом страшном определении.

Что такое система контроля версий? Когда вы пишете программу, реферат, стихи, музыку или что-нибудь еще, то сложно предположить, что всё получается с первого раза. Обычно процесс носит итерационный характер: вы что-то пишете, а потом исправляете. В некоторых случаях исправления делают хуже, тогда вы возвращаетесь к предыдущей версии, например, покопавшись в своих заметках или черновиках. Система контроля версий позволяет сохранять промежуточные версии ваших файлов, а в случае необходимости "возвращаться" к любой сохраненной версии.

Ниже мы рассмотрим, какие команды позволяют добавлять файлы "под управление" системы контроля версий, сохранять копии и т.п. Сейчас же опишем основной принцип работы. Git по сути является базой данных (надеюсь, что это интуитивно понятное слово), которая хранит копии файлов. Текущая версия файлов составляет так называемую "рабочую директорию". Все исправления вносятся в файлы рабочей директории. В тот момент, когда вы решили, что в рабочей директории появилось что-то логически законченное (например, вы закончили главу своего нового романа или исправили опечатку в программе), то вы можете "сохранить" в git состояние рабочей директории и продолжить вносить исправления дальше. Каждое "сохранение" делается с комментарием, который обычно описывает суть изменений. Например, "исправлена ошибка деления на ноль", "сцена в кафе" и т.п. Git позволяет просматривать историю изменений, сравнивать версии между собой (что было изменено в одной версии по сравнению с другой), возвращать состояние рабочей директории и т.п.

Что означает слово распределенная? Это немного сложнее. Хотя git может использоваться в "персональном режиме", основные его преимущества проявляются при совместной работы нескольких человек над одним проектом. Именно в этом случае и возникает необходимость в распределенности. Как вы уже знаете, в git есть база данных истории изменений файлов проекта. Обычно есть "центральная" база данных (например, на сервере github.com) и ее копии на компьютерах соавторов. Когда вы "сохраняете" свои изменения, вы изменяете свою локальную копию базы данных git. Если вы хотите, чтобы ваши изменения стали видны другим разработчикам, вам нужно "опубликовать" свои изменения в "центральной" (общей) базе. Это называется push. Если же вы хотите получить чужие изменения, то нужно сначала обновить свою локальную базу git (ту, что на вашем компьютере) в соответствии с изменениями на сервере, а потом обновить файлы. Распределенность git означает, что у каждого соавтора есть своя локальная копия общей базы данных, причем эти копии могут отличаться друг от друга (у одного пользователя "устаревшая", у другого — с исправлениями, которые еще не опали на сервер).

В несколько упрощенном виде последовательность действий при работе с git выглядит следующим образом.

  1. На сервере создается репозитарий для нового проекта. В нем может не быть файлов.
  2. На рабочем компьютере каждого соавтора создается копия этого проекта с помощью команжы git clone. При этом на каждом компьютере появляется рабочая директория и база git. Это выполняется один раз. Следующие действия выполняются многократно.
  3. Вносятся исправления в файлы рабочей директории.
  4. Исправления сохраняются в локальной базе git. Команды git add и git commit.
  5. С сервера скачивается измененная база данных. git fetch (При этом состояние файлов в рабочей директории не изменяться.)
  6. Изменения других пользователей применяются к текущей файлам текущей директории. git rebase
  7. Локальная база "проталкивается" на сервер. git push. Ваши исправления становятся доступны другим авторам (они могут их получить командой git fetch).

Команды для типовых действий

Git является довольно сложной системой с большим количеством команд. Более подробно о командах можно почитать по ссылке, мы же ограничимся рассмотрением наиболее простых операций.

Как добавить новый файл или директорию? Если вы просто создадите файл в рабочей директории, то он еще не будет контролироваться git. Для этого нужно выполнить команду git add filename, где filename заменяется на нужное имя файла. Аналогично нужно поступить и с новой директорией. Если вы хотите добавить несколько файлов, то можно либо выполнить команду git add несколько раз, либо указать несколько файлов через пробел.

Как посмотреть сделанные исправления? Какие файлы и как были изменены? Это делается командой git status или git status . (в конце команды стоит пробел и точка), если нужно посмотреть исправления в текущей директории, а не во всем проекте.

Чем текущая версия файла с именем filename (в рабочей директории) отличается от последней сохраненной в git версии этого файла? Что в нем было изменено с момента последнего сохранения? git diff filename. Если не указывать имя файла, то команда git diff выдаст все изменения (во всех файлах).

Как сохранить сделанные изменения? git commit -m "Описание изменений" file1 file2, где file1 и file2 — имена файлов, которые нужно сохранить. В этой команде можно перечислять произвольное количество файлов. Commit является набором изменений файлов, которые сохраняются в git как одно целое. Команда commit изменяет базу git на вашем компьютере.

Как получить исправления других авторов? Делается в два этапа. git fetch — скачать базу данных с сервера на свой компьютер. Обновляются только внутренние файлы git. git rebase — изменить файлы в рабочей директории.

Как опубликовать свои изменения? git push. Команда git передает вашу локальную базу на сервер. Обычно перед этим скачивают изменения других пользователей.

История изменений и rebase

Историю изменения файлов можно представлять в виде последовательности состояний файлов. В простейшем случае история линейна. Например, состояние X может соответствовать пустому репозитарию, в котором нет ни одного файла. Состояние Y — созданию первого файла (или нескольких файлов, это не имеет принципиального значения). Предположим, что в этот момент вы скопировали репозитарий на свой компьютер с помощью команды git clone и начали в нем что-то исправлять. На сервере и на вашем компьютере записана история состояний

X Y
Когда вы фиксируете свои изменения (команда git commit), вы создаете правила Y->Z: какие действия нужно применить к файлам в состоянии Y чтобы получить ваши исправления. Команда commit изменяет внутренние файлы git на вашем компьютере. То есть на вашем компьютере история уже представляется тройкой состояний X Y Z, а на сервере это всё ещё X Y.

Теперь вы хотите протолкнуть свои исправления на сервер чтобы они стали доступны другим пользователям. Вы выполняете git push и тут выясняется, что вас кто-то опередил. То есть текущая история на сервере имеет вид

X Y W
Новое изменение W нужно скачать на свой компьютер. Это делает git fetch. А потом выполнить git rebase. Команда git rebase делает так, что ваши преобразования Y->Z "переносятся" на состояние W. Как будто Вы раньше скачали не состояние Y, а W. То есть изменения становятся W->Z.

Конфликты

При совместной работе нескольких человек над одним проектом могут возникнуть конфликты при редактировании файлов. Представьте себе ситуацию, когда два человека по-разному исправили одну строчку в файле. Автоматически определить, какое из двух исправлений является правильным, невозможно. Такая ситуация называется конфликтом и требует, чтобы человек принял решение.

Исправление конфликтов может быть трудоемким. В случае, когда каждый соавтор исправляет только "свои" файлы, то есть гарантируется, что каждый файл исправляет только один автор, конфликты возникнуть не могут. Поэтому мы не будем про них говорить. Будем считать, что вам запрещено изменять чужие файлы.

Работа с нескольких компьютеров

Если вам нужно работать на нескольких компьютерах одновременно, то git может упростить эту задачу. Например, вы можете написать программу на домашнем компьютере и "толкнуть" изменения на сервер, а потом в дисплейном классе скачать эту версию. После внесения исправлений (в конце пары) сохрани исправления и "толкнуть" их на сервер.