Git – доминирующая система контроля версий в IT на данный момент. Основная причина – в том, что в Git заложен крайне мощный функционал, с помощью которого можно решать самые сложные конфликты слияния функционалов, реализованных разными разработчиками (git merge). Кроме того, Git – действительно быстрый и легковесный, внутри себя он использует сложную схему запоминания изменений, исключающую дублирование информации (насколько это возможно, по крайней мере). В Git commit – самая частая команда, которой пользуются разработчики, потому что именно коммит является «логической единицей версионирования». Ниже мы объясним, что на самом деле значит коммит в локальных репозиториях и как выполнить коммит – а также как отменить коммит, если что-то пошло не так. Мы предполагаем, что вы уже имеете базовое представление о Git, поэтому начнем не с «Что такое репозиторий и ветка master», а сразу с устройства локального репозитория. Кроме того, здесь мы не будем рассматривать команды Git, не относящиеся напрямую к коммитам – git pull, git branch, git checkout, git rebase, cherry-pick и так далее.
Итак, вы скачали из удаленного репозитория клон проекта, создали свою ветку и работаете в ней. Например, вы хотите создать новый функционал для приложения – для этого вам нужно создать пару новых файлов, затем – наполнить их кодом, после этого – локально протестировать, что все работает. На текущий момент в вашем локальном репозитории хранится копия репозитория с GitHub, отличий (кроме новой ветки) пока что нет. Копия хранится в папке на вашем компьютере, и это важно, потому что в деле участвуют сразу 2 файловые системы: собственная файловая система вашей операционной системы и файловая система Git, которая отслеживает все изменения в файлах рабочей папки (кроме тех файлов, которые вы с помощью .gitignore пометили как неотслеживаемые).
Итак, вы создали новый файл и наполнили его кодом. Что изменилось? В вашей файловой системе на локальном компьютере появился новый файл, в котором хранятся какие-то данные. Вы его видите и можете открыть. Git его тоже видит, но в свою файловую систему не вносит – этот процесс может запустить только пользователь (хотя Git говорит, что этот файл «modified»). Если вы хотите внести новый или измененный файл в файловую систему, вам нужно ввести команду «git add имя_файла» – тогда Git добавит его «у себя». Файл получит статус «staged» – подготовлен ко внесению в ветку (что и будет являться коммитом).
Вот эта область, в которую вы вносите файлы командой git add, называется «индексом». Индекс можно рассматривать как песочницу – можете добавлять новые файлы, можете удалять их командой git rm, и никто вам ничего не скажет, потому что идет нормальный процесс разработки. То, что происходило в staging area, остается в staging area. Но постепенно в индексе (кстати, еще одно название – область подготовленных файлов) скапливаются файлы, которые составляют «правильную» реализацию той фичи, которую вы сейчас делаете. Рано или поздно вы поймете, что часть функционала (или весь функционал) больше не нужно будет менять – здесь и выходит на сцену git commit. Commit – это команда, создающая логический узел на ветке разработки. После того, как вы создадите коммит, в него перенесутся все новые файлы, которые находились в staging area – и эти файлы станут видны всем, кто скачает ваш репозиторий. А если вы сделаете git push, то ваш локальный репозиторий пошлет в центральный репозиторий все новые коммиты – и тогда ваши изменения увидят все, кто склонирует центральный репозиторий.
Кратко:
Схематически это можно представить так:
Рисунок1
Если пока не до конца поняли – вот вам аналогия: вы пишете главу книги, и начинаете с черновика – что-то в нем пишете, что-то зачеркиваете, снова пишете и переписываете. В черновике крайне сложно разобраться, потому что везде начеркано, но на то он и черновик. В конце концов вы привели текст в черновике к состоянию, которое вас удовлетворяет, после чего – переписываете слово в слово черновик на чистовик. Написав еще пару глав таким же образом, вы отправляете текст редактору на проверку. Так вот, черновик – это staging area (git add), чистовик – это коммит (git commit), передача текста редактору – это пуш в центральный репозиторий (git push).
git commit -m “сообщение”
В сообщении нужно указать, что этот коммит в себе несет, обычная формула: «this commit…», например: «this commit adds a login button». Если вы не укажете сообщение в команде git commit – Гит откроет стандартный для вашей ОС редактор текста и попросит вас ввести сообщение, коммитить без пояснительного сообщения нельзя.
А вот тут все сложно. Пока файлы находятся в staging area, вы можете удалять их простым git rm; если же вы уже закоммитили изменения, просто так «выдрать» их из ветки не получится. Какие есть варианты:
Если вы уже запушили коммит в центральный репозиторий, а теперь пытаетесь удалить его – вы можете создать большие проблемы с синхронизацией для всех участников разработки, такие вещи лучше обсуждать с релиз-менеджером (или девопсом, на которого повесили эту обязанность).
К слову, если вы уже удалили коммит (даже с --hard) – его все еще можно восстановить, хотя об этом знают далеко не все. Дело в том, что в Гит есть чудесная команда git reflog, которая показывает все состояния, в которых находился HEAD (и все коммиты, на которые он указывал). После того, как вы найдете нужное состояние, можно будет перейти на него по ссылке из самого reflog (git checkout) – и вы окажетесь в счастливом прошлом, в котором чудовищной ошибки не произошло. Правда, reflog хорошо работает ровно до тех пор, пока ваши изменения не попали в центральный репозиторий – там все становится сложнее.