[Из песочницы] Git: советы новичкам – часть 1
В Playrix приходит много новых сотрудников и большинство из них не работали с Git. Особенно это касается гейм-дизайнеров и художников. Хотя и для программистов это не редкость — опыт работы с другими системами контроля версий не слишком помогает. Например, часто встречается опыт работы с SVN. Но Git заметно отличается по идеологии. Заучить, какие кнопки нажимать, в большинстве случаев не сложно, но шаг в сторону — и уже трудно понять, что происходит.
Поэтому мы решили написать ознакомительный материал. Мы поговорим о системе контроля версий и логике её работы, с самых азов. С Git можно работать с помощью разных клиентов, потому в статье не пойдет речь об интерфейсе пользователя. Это может показаться непривычным, но это сделано намеренно. Вместо этого мы сфокусируемся на рабочем каталоге, коммитах, ветках, командах pull, push и прочих. Когда вы разберетесь в этих понятиях, вам останется выбрать один из Git-клиентов и освоить его интерфейс.
Глава 1. Первое знакомство
Представьте, что у вас есть каталог Work, в котором вы будете работать. Мы будем называть его рабочим каталогом. В нём лежит текстовый файл document.txt. Вы изо дня в день работаете с этим файлом, добавляете в него новый текст, ненужный удаляете, что-то изменяете. Внезапно вам потребовался текст, который вы пару дней назад удалили. Что делать? Если вы не используете систему контроля версий (СКВ), то этот текст не восстановить. А если вы пользуетесь СКВ — это не будет проблемой.
Как это работает? Вы всегда можете отправить свой файл в СКВ, и она его запомнит. Это называется «закоммитить файл» (команда commit). Если вы делаете такие коммиты после всех важных изменений файла, то внутри СКВ образуется множество копий разных его версий. Вы не увидите эти копии в вашем каталоге Work — там, по-прежнему будет лежать лишь один файл. Но все его копии, которые вы коммитили, можно при необходимости достать из СКВ. Там вы сможете посмотреть список всех версий вашего файла и проверить те строки, которые меняли в каждой версии. Удобно, не правда ли?
Предположим, вы меняете свой файл и даже сделали несколько его коммитов. СКВ запомнила закоммиченные версии файла (для краткости будем называть закоммиченную версию файла просто «коммитом»). Теперь выполним команду push — она отсылает ваши коммиты на сервер. В этом есть две главные цели:
- Сохранность (если у вас испортится компьютер, вся история изменений файла останется на сервере);
- Возможность нескольким людям одновременно работать над одним файлом.
Как выглядит одновременная работа? У других сотрудников на компьютере тоже есть папка Work и в ней тоже есть файл document.txt. Если вы отредактировали файл, сделали коммит и пуш, то ваши изменения попадут на сервер. Если другой человек выполнит команду pull, с сервера скачаются ваши изменения и человек увидит их в своём файле.
Так над одним и тем же файлом могут работать сразу несколько сотрудников. Они периодически забирают себе изменения других людей (pull), а также вносят свои изменения, коммитят их (commit), и отправляют на сервер (push). Оттуда их смогут забрать другие сотрудники.
Интересно, что команда pull скачивает с сервера не только последнюю версию файла, но и все предыдущие, которые кто-либо коммитил. То есть, все коммиты вашего коллеги будут храниться не только на его компьютере, но теперь и на вашем тоже. Благодаря этому можно просмотреть всю историю файла: кто, когда и какие строчки в нём менял.
Для контроля версий мы используем программу Git. Для просмотра истории изменения файла Git не обращается к серверу. Он просто показывает все версии файла, которые уже хранятся на вашем компьютере. Версии файла, которые отредактировали другие, попадают на ваш компьютер после команды pull.
Итоги:
- Мы доверили Git следить за нашей рабочей папкой;
- В папке есть текстовый файл, в котором работают наши коллеги;
- Периодически мы забираем изменения других сотрудников в этом файле (команда pull);
- А также мы сами меняем этот файл и делаем коммиты, позволяя Git запомнить новую версию файла. Потом мы отправляем наши коммиты на сервер (команда push). Отправлять можно как один коммит, так и сразу несколько. Но лучше пушить почаще, чтобы сотрудники видели актуальную версию файла. Другое дело, если работа не закончена — такую «рабочую» версию файла пушить, конечно, не стоит. Ведь вы создадите неудобства другим сотрудникам.
Убедитесь, что вы чётко поняли разницу между изменением файла, его коммитом и «пушем».
Поздравляем! Вы познакомились с основными возможностями системы контроля версий Git. Обратите внимание, мы специально не описываем, как вызывать команды. Потому что есть несколько Git-клиентов с разным интерфейсом. Чуть позже вы выберите один и изучите его. А пока мы просто расскажем, какие есть команды и что они делают.
Глава 2. Удалённый репозиторий, который никто не удалял
Место, куда Git сохраняет ваш файл после каждого коммита, называют локальным репозиторием. Он находится на вашем компьютере — потому и «локальный». Выше мы говорили, что команда push посылает ваши коммиты на сервер. Так вот, в Git не совсем верно говорить «сервер» — правильнее называть это «удалённым репозиторием». «Удалённый» — не потому, что его кто-то удалил, а потому, что он далеко (не у вас на компьютере). В нашем случае удалённый репозиторий находится на сайте GitHub. По своей структуре это такой же репозиторий, как у вас на компьютере. Он так же хранит коммиты. Команда push посылает коммиты с вашего локального репозитория в удалённый, а pull наоборот — забирает новые из удалённого репозитория в ваш локальный. Откуда там взялись свежие коммиты? Их туда отправили другие сотрудники.
Писать каждый раз «удалённый репозиторий» слишком долго. В Git его называют origin. Такова традиция. Дальше мы для краткости будем использовать термин origin вместо «удалённый репозиторий».
Глава 3. Углубляемся в детали
Пора углубиться в важные технические детали. Их довольно много, но понимание логики работы Git пригодится вам в работе. Так что придется набраться терпения.
Конечно, работа в вашем рабочем каталоге обычно ведётся не только в одном файле. Git позволяет работать с каким угодно количеством файлов внутри вашего рабочего каталога, а также внутри вложенных каталогов.
Каждый коммит может запоминать изменения сразу в нескольких файлах. Хорошая практика — в один коммит включать только те изменения, которые логически связаны между собой. Не коммитьте одновременно множество разных изменений — в их истории будет трудно разобраться и вам, и другим сотрудникам.
Если вы добавили в ваш рабочий каталог новый файл и хотите, чтобы его тоже можно было коммитить (и чтобы его увидели другие сотрудники), вам нужно самому добавить файл в Git. Это делает команда add. Пока вы этого не сделали, Git не будет включать в коммиты ваш новый файл. Также можно создавать подкаталоги в рабочем каталоге. Файлы в них нужно добавить в Git тоже с помощью команды add.
Важно понять, что часть файлов в вашем рабочем каталоге может находиться под контролем Git, а часть — нет (например, логи). Следить за этим и добавлять новые файлы в Git — ваша задача.
Кстати, а откуда ваш рабочий каталог вообще возьмётся на вашем компьютере? Он там появится после того, как вы заберёте его с сервера (команда clone).
При каждом коммите нужно добавлять комментарий. В нем кратко, но информативно описывать — какие изменения вы сейчас коммитите.
Git может вам показать список файлов, которые вы изменили с момента предыдущего коммита. Вы не обязаны коммитить их все сразу. Можете выбрать группу файлов, изменения в которых логически связаны, и закоммитить их. Потом выбрать другую — сделать ещё один коммит и так далее. Важно разбивать коммиты на логические.
Перед тем, как сделать push (отправить коммиты в удалённый репозиторий origin), нужно обязательно сначала сделать pull (забрать последние изменения других людей, которые они отправили в origin). Если этого не сделать, система не даст вам выполнить push (появится сообщение об ошибке). Когда узнаете больше об особенностях работы Git, вы поймёте почему так происходит, а пока просто запомните это правило.
Глава 4. Незакоммиченные изменения
Если вы поменяли какие-то файлы, но ещё не закоммитили их, то говорят, что в вашем рабочем каталоге есть незакоммиченные изменения. Ряд команд Git нельзя выполнить в таком состоянии. Например, pull или checkout (переключение файлов рабочей копии на другой коммит). Какие варианты выхода из этой ситуации?
- Если эти изменения не нужны, то можно отменить незакоммиченые изменения. При этом файл вернётся в состояние последнего коммита;
- Если изменения полезные, то можно их закоммитить;
- Ещё можно временно спрятать эти изменения (команда stash). При этом в рабочем каталоге ваши изменения откатятся. Позже вы сможете вернуть спрятанные изменения в рабочий каталог.
Глава 5. Конфликты и их разрешение
Когда вы забираете изменения из origin могут возникнуть конфликты. Это происходит, если:
- Вы изменили некоторые строчки в текстовом файле, закоммитили изменения, но ещё не сделали push.
- В это же время кто-то изменил эти же строчки в файле и успел отправить изменения в origin.
- Вы делаете pull, чтобы забрать чужие изменения. Git пытается объединить чужие изменения с вашими и обнаруживает, что изменены одни и те же строчки. Это называется конфликт (conflict).
Если это произошло, вам придётся разрешить конфликты вручную во всех файлах, где они возникли. Для каждой группы конфликтных строчек вы увидите два варианта — который написали вы и который написал кто-то другой.
Вам нужно выбрать, какой из этих вариантов оставить в результате слияния ваших изменений. Или можно вручную написать какой-то третий вариант — если нужно более тонкое объединение, чем просто копия одного из вариантов.
Дальше повторяем такие же действия для каждой группы конфликтных строк в каждом файле, в котором есть конфликты.
Если конфликт не в текстовом файле, а в бинарном (например, картинка), то там никаких строчек, конечно, нет. Тогда нужно целиком выбрать какой из файлов оставить после слияния — вашу версию файла или чужую. Если вы не уверены, как правильно — свяжитесь с тем, кто менял этот файл последним (это можно узнать в истории изменений файла) и обсудите с ним чья версия файла должна остаться. Не стоит всегда брать свои версии не разобравшись — вдруг изменения другого человека правильнее. А вы их затрёте своими изменениями, если разрешите конфликт в свою пользу. Это явно будет нехорошо.
Когда все конфликты разрешены, можно продолжить операцию, которая была прервана из-за конфликта — обычно это операции pull, merge, rebase.
Если вас напугали конфликты и вы не готовы их разрешать прямо сейчас, можно выполнить команду abort. Она откатит состояние рабочего каталога — сделает его таким, каким он был до начала операции, которая вызвала конфликт.
Глава 6. Слепки
Представьте текущее состояние одновременно всех файлов в вашем рабочем каталоге.
Представили? Назовём это состояние рабочего каталога «слепком». Каждый раз, когда вы делаете коммит очередных изменённых файлов, Git запоминает новый слепок (состояние всех файлов рабочего каталога). Понятие «слепка» мы будем использовать в следующей главе.
Примечание 1: Слепок — это НЕ состояние только лишь изменённых файлов. Это состояние ВСЕХ файлов рабочего каталога.
Примечание 2: Когда мы говорим «все файлы рабочего каталога», то, конечно, имеем в виду файлы под контролем Git. О всех остальных файлах Git ничего не знает.
Глава 7. История изменений и её визуальное представление
Историю изменений файлов рабочего каталога можно изобразить в таком виде:
Каждый кружок — это один коммит. На картинке показаны коммиты, которые сделаны один за другим. Это графическое представление истории коммитов.
Кстати, коммит можно рассматривать одним из двух способов:
- Коммит, как изменение файлов с предыдущего коммита;
- Коммит, как слепок — новое состояние всех файлов рабочего каталога, которое возникло после закоммиченных изменений.
В каких-то случаях удобно рассматривать историю, как цепочку изменений, а в каких-то — как цепочку слепков. Так что научитесь мысленно оперировать обоими вариантами.
Вот пример, когда удобно рассматривать «слепки». Представьте, что вы хотите посмотреть, как выглядел ваш рабочий каталог три коммита назад. Это легко устроить. Берём историю (см. картинку), отсчитываем 3 кружка (коммита) назад и говорим Git: «Хочу посмотреть, как выглядел рабочий каталог вот после этого коммита». Git изменит файлы в рабочем каталоге соответственно. Другими словами, мы переключили рабочий каталог на слепок этого коммита (или просто «на этот коммит»).
В следующей части статьи мы расскажем про:
- Ветки
- Слияние веток
- Несколько мержей из ветки А в ветку В.
- Мерж между ветками в обе стороны
- Коммиты и их хеши
- Ветки и указатели
- Указатель head
- Указатель origin\master