Git

Git #

Зачем? #

Никто не думает, что ему нужна программа для контроля версий своего проекта ровно до тех пор, пока не станет слишком поздно.

А ещё никто не любит терять важные документы, либо часы своего драгоценного времени из-за сломанной флешки или отключенного света. А ещё обиднее ситуация, когда ты написал крайне заумную фичу, полюбовался ею и пошёл писать следующую. Но случился казус — новая фича сломала программу, Ctrl+Z уже не может вернуть к предыдущей рабочей версии, а сам ты не можешь вспомнить как восстановить прошлое состояние проекта…

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

Но самая большая проблема возникает тогда, когда над проектом работает больше одного человека. Облачные системы синхронизации типа GDrive, YaDisk, Dropbox не сильны в решении конфликтов при синхронизации и только создадут головную боль. Как объединять две версии проекта с таким подходом даже не хочется себе представлять…

На решение всех этих проблем приходят системы контроля версий: Git и Mercurial. У обеих систем есть свои приложения, но здесь рассмотрим только Git, так как он является намного более популярным и имеет множество развитых проектов, предоставляющих возможность бесплатного хранения проектов, таких как GitHub.

Установка #

Linux #

Установить git можно с помощью пакетного менеджера твоей системы: например, sudo apt install git или sudo pacman -S git.

MacOS #

На MacOS установить git можно с помощью пакетного менеджера Homebrew. Если ты ещё не установил brew, можешь сделать это с помощью команды в терминале:

  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" 

После этого установить git можно командой brew install git.

Windows #

Программу для установки можно скачать здесь . Изменять какие-то параметры установки не обязательно, поэтому для простой и стандартной установки достаточно просто нажимать на Next.

Git на windows используется через установленную программу git bash, вместе с которой устанавливается базовое окружение Unix систем (программы ls, cd и т.д.).

Базовые команды #

Для того, чтобы начать пользоваться git’ом достаточно всего нескольких команд и некоторого понимания основных понятий.

Репозиторий — это хранилище всех зафиксированных версий всех отслеживаемых объектов в папке проекта.

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

Состояния файлов #

В любом репозитории файлы находятся в четырёх состояниях:

  • Untracked (не отслеживаемые) — файлы, которые находятся в папке репозитория, но их изменения никак не влияют на само состояние репозитория;
  • Unstaged — сам файл отслеживается git’ом, но изменения относительно предыдущего коммита не будут зафиксированы;
  • Staged — означает, что файл и отслеживается git’ом, и изменения будут зафиксированы;
  • Commited — в файле нет изменений относительно предыдущего коммита.

Необходимые команды #

Для создания репозитория достаточно ввести git init в папке с проектом. После этого все файлы в этой папке будут считаться Untracked.

С помощью команды git add [files] можно перевести файлы из состояния Untracked или Unstaged в состояние Staged. Если отслеживаемый файл после выполнения этой команды файл был изменён, то необходимо снова его добавить в Stage.

Перед фиксированием изменений полезно проверить состояние репозитория. Команда git status выведет список состояний файлов в текущей папке.

  $ git status
  On branch master
  Changes to be committed:
    (use "git restore --staged <file>..." to unstage)
    modified:   file.txt

  Changes not staged for commit:
    (use "git add <file>..." to update what will be committed)
    (use "git restore <file>..." to discard changes in working directory)
    modified:   another.txt

  Untracked files:
    (use "git add <file>..." to include in what will be committed)
    third.txt

Таким образом можно проверить все ли изменения будут зафиксированы.

Само фиксирование изменений происходит с помощью команды git commit. Для коммита с простым описанием достаточно команды git commit -m "<message>". Одна строка <message> будет добавлена к коммиту и записана в хранилище. Обычно, простого описания будет достаточно. Но если необходимо более развёрнутое и многострочное описание, то можно выполнить команду git commit без аргументов. Будет вызван текстовый редактор (если не настраивать иначе, то скорее всего будет вызван Vim).

Распространение репозитория на другие компьютеры #

С помощью команд из предыдущего пункта можно вести простую прямую историю репозитория на одном компьютере. Но репозиторий, лежащий на одном компьютере не очень полезен, поэтому нужно понять как его распространить.

Github #

Для хранения репозиториев зачастую используются сервисы типа GitHub . Несмотря на то, что технически git — это распределённая и децентрализованная система контроля версий, удобно принять один из репозиториев за центральный и синхронизировать свой репозиторий с ним.

Далее будет подразумеваться, что для хранения репозиториев используется GitHub, поэтому будет полезно на нём зарегистрироваться.

Для создания нового репозитория нужно на главной странице сервиса нажать на зелёную кнопку New, чтобы открылась следующая страница:

Создание нового репозитория

После нажатия на кнопку Create repository будет открыта страница с новым репозиторием в которой сразу же предложат скопировать на него ссылку:

Новый репозиторий

Так и поступим.

Внешние репозитории #

Так как данный репозиторий хранится на серверах GitHub, нужно добавить ссылку на него в локальный репозиторий. Делается это со помощью команды git remote. Так как внешних репозиториев может быть несколько, каждому из них нужно присвоить какое-то имя. Обычно основной внешний репозиторий называют origin. Таким образом, вся команда для добавления внешнего репозитория:

  git remote add <remote-url>

Для моего только что созданного репозитория <remote-url> равна https://github.com/saintruler/git-article.git.

После этого для синхронизации с этим репозиторием можно написать git push -u origin master. В этой команде мы указываем, что ветка master должна быть отправлена на внешний репозиторий origin. После выполнения этой команды один раз эта связь будет записана в репозитории и для синхронизации ветки master будет достаточно написать просто git push.

Если внешний репозиторий был обновлён с другого компьютера, то для синхронизации текущего компьютера нужна команда git pull.

Клонирование репозиториев #

Но для изменения репозитория с другого компьютера нужно чтобы этот репозиторий появился на другом компьютере. Для этого используется команда git clone. Хотя и можно скопировать репозиторий на флешку или запаковать и передать в мессенджере или облаке, клонирование является основным и самым богоугодным способом перенести свой репозиторий на другой компьютер.

При клонировании репозитория ссылка на клонируемый репозиторий сама добавляется как внешний репозиторий origin.

Непосредственно контролирование версий #

Ветки #

Иногда очень хочется вести две параллельные версии проекта, но при этом очень не хочется что-либо сломать. Для этого предусмотрена возможность создания веток. В новом репозитории создаётся одна ветка — master. Чтобы удостовериться в этом можно вывести список всех веток командой git branch. Текущая ветка будет выделена в этом списке.

Для создания новой ветки используется команда git branch <name>. При этом репозиторий остаётся на старой ветке. Переключиться на другую ветку можно командой git checkout <name>. Если же хочется создать новую ветку и сразу на неё переключиться — git checkout -b <name>.

Новая ветка создаётся на основе той, на которой ты находился при её создании. Ветки можно рассматривать как альтернативную историю репозитория, но это не значит, что ветки разошлись навсегда. Ветки с общей историей можно объединять обратно с помощью команды git merge.

Объединение веток #

Команда git merge <other-branch> добавляет изменения из <other-branch> в текущую ветку. При объединении веток могут возникнуть конфликты — обычно это изменение одного и того же места в одном и том же файле.

Именно конфликты при объединении веток обычно бывают непонятны новичкам и из-за этого вызывают множество проблем. Для облегчения решения конфликтов существуют различные внешние программы. Достаточно простой и удобной является программа Meld . Она позволяет производить решение конфликтов в трёхпанельном интерфейсе для того, чтобы проконтролировать изменения из какой ветки в итоге будут приняты. После установки этой программы нужно указать git’у, что решение конфликтов будет проводится именно ею. Это делается командой git config --global merge.tool meld. После этого можно запустить процесс решения конфликтов командой git mergetool.

Stash #

Если на ветке присутствуют некоторые незакоммиченные изменения, которые могут вступить в конфликт с изменениями с другой ветки при слиянии, либо с изменениями с этой же ветки при выполнении git pull, то можно просто положить их в “копилку” (stash), выполнить нужное действие и вытащить из этой копилки.

Для того, чтобы положить изменения в копилку выполняется команда git stash. Увидеть все “спрятанные” изменения можно командой git stash list. Все эти сохранённые изменения нумеруются, поэтому их можно обратно применить на ветку командой git stash pop <number>. После этого данные изменения из копилки удалятся. Если нужно сохранить изменения в копилке, то вместо pop следует использовать apply. git stash drop <number> удаляет ненужную запись в копилке.

Revert и log #

Когда изменения уже закоммичены, но стало понятно, что они либо что-то ломают, либо вообще не нужны, то их можно откатить командой git revert <commit-hash>. После выполнения этой команды могут возникнуть конфликты, которые также можно решать через git mergetool. Когда все конфликты в файлах будут решены, эти файлы нужно будет добавить через git add и закоммитить.

Но нужно заметить, что все коммиты, которые появились после восстановленного коммита останутся в истории. То есть git не перезаписывает историю репозитория, а создаёт новый коммит, который со старым содержанием. При таком подходе у тебя не получится испортить репозиторий и отстрелить самому себе ноги, что хорошо. В git’е существуют команды, которые могут перезаписать историю репозитория, но в этой статье они не будут рассматриваться, так как в нормальных обстоятельствах при работе со своими собственными репозиториями не понадобятся.

Чтобы узнать хеш коммита, можно использовать команду git log. С её помощью можно посмотреть всю зафиксированную историю текущей ветки. У данной команды есть много параметров для изменения формата вывода, которые можно посмотреть в соответствующем мануале man git log. Например, чтобы увидеть дерево репозитория в более краткой форме с визуальным отображением работы в ветках можно использовать git log --oneline --graph.

Поиск информации #

Про работу с git’ом есть огромное количество информации в сети (эта страница в том числе), но основным способом изучения доступных команд являются

Github Flow #

Наиболее полезным git становится в случае работы над одним репозиторием в команде. Для организации работы над репозиторием можно использовать уже продуманные за нас процессы, например github flow. Прочитать про них можно на этих сайтах:

Автор: Андрей Гущин