02 февраля 2023

🔶 Гайд по работе с деревом коммитов Git для начинающих

iOS-developer, ИТ-переводчица, пишу статьи и гайды.
Гайд охватывает основы Git, включая то, что это такое и зачем он используется. Также обсуждаются такие концепции Git, как коммиты, ветки, слияние и сброс изменений. Руководство написано для людей, практически не имеющих опыта работы с Git.
🔶 Гайд по работе с деревом коммитов Git для начинающих
Данная статья является переводом. Автор: Zach Musgrave. Ссылка на оригинал.

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

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

Но, в конце концов, я изучил и понял его. Пусть мне и не нравится интерфейс git, но я действительно полюбил продукт, когда понял, что он делает. Но прежде чем я поделюсь секретами... Позорно признаюсь. Привет, меня зовут Зак, я инженер-программист, но я... я wordcel (прим. пер. человек с развитыми ораторскими способностями, испытывающий сложности с визуализацией предметов и собственных идей). Прошло 3 года, 4 месяца и 11 дней с тех пор, как я в последний раз представлял вращение объемной фигуры.

Wordcel испытывает сложности при работе с git, потому что это инструмент от shape rotator (прим. пер. человек с развитым пространственным мышлением, которому сложно словесно выражать свои мысли) для shape rotator. Но благодаря долгому обучению и практике, я пришел к более глубокому понимаю и теперь могу поделиться этим знанием.

Я предполагаю, что вы понимаете идею системы контроля версий немного абстрактно: она позволяет вам сохранять несколько версий ваших файлов и возвращать любую предыдущую версию, если вы что-то напутали. Я хочу поговорить о том, что выгодно отличает git, а именно дерево коммитов.

Гайд от wordcel

Первое, что вы должны понять о git, это то, что он хранит всю свою историю в дереве:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Дерево коммитов из веб-учебника по git. Это и все последующие изображены взяты отсюда.

Вы можете подумать, что это что-то для shape rotator. Не паникуйте! На самом деле это не так уж и сложно, когда вы понимаете, что происходит. Просто люди, которые строят такие схемы, настолько shape rotator, что они забыли о том, как говорить со скромными wordcel.

Вот как выглядела бы эта схема, если бы она была вам полезна.

🔶 Гайд по работе с деревом коммитов Git для начинающих

Это история вашего файла. Вы начали с первой версии, которую вы зафиксировали с комментарием «первый черновик». Затем вы написали второй черновик и зафиксировали эту версию, затем, наконец, сделали копии и зафиксировали их. Итак, у вас есть список из трех версий вашего файла в том порядке, в котором вы их сделали.

Далее добавим еще пару деталей.

🔶 Гайд по работе с деревом коммитов Git для начинающих

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

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

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека программиста»

Branches (Ветки)

В git вы можете одновременно запускать несколько разных черновиков одного и того же файла. Думайте об этом как об альтернативных линиях времени для файла, параллельных версиях реальности, где все пошло по-другому. Как вы, наверное, догадались, эти временные шкалы и есть то, что git называет branch или ветками.

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

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

🔶 Гайд по работе с деревом коммитов Git для начинающих

Колонка коммитов слева — это ваши новые правки в первом черновике. Но было бы ошибкой говорить, что теперь у вас есть две разные копии вашего файла (на самом деле, у вас есть пять разных копий, по одной для каждого сделанного вами коммита). Точнее будет сказать, что у вас есть две альтернативные истории файла. Теперь для этого файла есть две альтернативные временные шкалы, которые разошлись после создания первого черновика. На каждой временной шкале вы вносили различный набор правок, поэтому конечный файл на каждой временной шкале также отличается.

На дереве коммитов отмечены альтернативные временные шкалы:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Было бы еще одной ошибкой оставить в этой схеме цветные блоки временной шкалы, потому что они на самом деле не существуют в представлении git о мире. Ветка — это не временная шкала или история: это просто метка для коммита, у которого есть история. У каждого коммита есть родитель и, следовательно, история, но ветки просто помогают обозначать отдельные коммиты на дереве. В свое время я очень сильно из-за этого путался при изучении git.

Например, ничто не мешает вам ввести еще одну точку расхождения в коммите "second draft", чтобы вы могли отправить файл в еще одно место. git checkout позволяет сделать это. Если я использую эту команду:

        git checkout -b third-draft 0f240a
    

То получу третью ветку в коммите с этой меткой. Удаление временных шкал и замена их метками ветвей дает нам следующее:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Итак, у меня есть 3 ветки: take1, take2 и take3, каждая из которых относится к другому коммиту на дереве. Все они имеют некоторые общие элементы своей истории, поэтому нет смысла говорить о них, как о независимых сущностях – это просто метки на основном дереве. Особенно актуально это в том случае, если речь идет о слиянии.

Merging (Слияние)

Одна из основных причин, по которой git стал таким популярным, заключается в том, что он может довольно хорошо справляться с объединением двух веток. Это возможно благодаря дереву коммитов.

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

        git checkout take1
git merge take2
    

Чтобы выяснить, как объединить эти две ветки, git просматривает базовое дерево и выясняет, что произошло с обеими ветками с тех пор, как они разошлись. Место, где они разошлись, называется общим предком двух ветвей.

🔶 Гайд по работе с деревом коммитов Git для начинающих

Git объединяет файлы построчно с умом. Поэтому, пока вы не изменили одну и ту же строку в своем файле в обеих ветках, результатом вашего слияния будет файл с обоими наборами изменений, примененных к нему. Это создает новой коммит, который будет выглядеть так:

🔶 Гайд по работе с деревом коммитов Git для начинающих

У нового коммита, помеченного как acc518, есть двое родителей – двое коммитов, из которых он был получен. Поскольку мы «наложили» take2 на take1, метка ветки take1 теперь указывает на новый коммит, в то время как ветка take2 по-прежнему ссылается на тот же коммит, что и раньше.

Это особенно актуально при работе с другими людьми. Допустим, еще до merge, описанного выше, вы попросили свою подругу Сару улучшить код. Она внесла пару изменений в свою ветку, так что теперь дерево коммитов выглядит так:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Что происходит, когда вы хотите добавить ее изменения? Вы объединяете ветку Сары со своей:

        git merge sarah
    

Вот где действительно важно дерево коммитов. Как и раньше, git определит, где две ветки разошлись, и будет знать, что ему нужно учитывать только изменения с момента этого расхождения, только два коммита, которые Сара сделала, выделенные синим цветом ниже:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Наконец, мы видим дерево коммитов ниже. У нового коммита 7dfe0a есть двое родителей благодаря merge. Наша ветка take1 указывает на этот коммит, при этом метка ветки sarah не сдвинулась.

🔶 Гайд по работе с деревом коммитов Git для начинающих

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

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

Git reset без сброса изменений

Как и любая система контроля версий, git позволяет восстановить ваши файлы до любой предыдущей точки в истории. Это очень полезно, когда вы хотите исправить ошибку. Основной способ решения проблемы — это использование команды git reset --hard, которая берет метку извлеченной вами ветки и перемещает ее на предыдущий коммит в истории ветки, любой коммит, который вы выберете.

Но что происходит с изменениями, которые вы сделали после git reset? Куда они помещаются? Ну, они никуда не уходят, и как только вы поймете, что делает команда git reset, вам все станет понятно.

При использовании git в реальном мире, например, когда вы работаете с командой, у вас обычно есть ветка main, в которую никто не коммитит напрямую. Скорее, у каждого есть собственные ветки, над которыми они работают, и они объединяются в main в каком-то централизованно контролируемом месте, например, на GitHub.

Но любой, кто управлял этим рабочим процессом, в тот или иной момент забыл сначала создать ветку и совершил ошибку, сделав коммит непосредственно в main. Что теперь? Мне просто повторно клонировать репозиторий и начать заново? Если вы понимаете дерево коммитов git, то вам не нужно заморачиваться! Нет необходимости начинать заново, просто перемещайте метки веток.

Вот с чего мы начинаем: мы случайно сделали несколько коммитов непосредственно в main с момента нашей последней синхронизации с GitHub.

🔶 Гайд по работе с деревом коммитов Git для начинающих

Поэтому нам нужно отменить эти изменения в main, они усложнят нашу жизнь. Прежде чем мы это сделаем, давайте создадим ветку, чтобы сохранить нашу работу.

        git branch myWork
    

Команда git branch создает новую метку ветки на текущем коммите. Таким образом, дерево такое же, как и раньше, просто оно содержит дополнительную метку ветки, указывающую на самый последний коммит.

🔶 Гайд по работе с деревом коммитов Git для начинающих

Затем мы сбрасываем ветку main на нужный коммит.

        git reset --hard f2d6f2
    

git reset --hard перемещает текущую метку ветки в другое место в дереве коммитов. На самом деле это не отменяет результаты проделанной работы. После git reset наше дерево коммитов выглядит так же, но метки веток теперь указывают куда-то еще:

🔶 Гайд по работе с деревом коммитов Git для начинающих

Чтобы продолжить работу над нашими изменениями, мы снова переключаем наше рабочее пространство на ветку myWork, используя git checkout myWork.

Что насчет git rebase?

Нет.

Git — невероятно универсальный инструмент, который позволяет вам делать действительно сложные вещи с деревом коммитов. Некоторые очень умные shape rotator решили, что будет круто забрать набор коммитов, которые они сделали в одной ветке, и перенести их в другую ветку. Это переписывает историю репозитория, будто у этих коммитов все время был другой родитель.

Shape rotator всегда пытаются объяснить вам, что это не ужасно дурацкая идея с небольшой выгодой, но вы не должны верить их лжи.

Git rebase — инструмент тьмы, которому нельзя доверять даже в крайней нужде. Идите к свету – используйте merge. Я не буду отвечать на вопросы по этому поводу.

Заключение

Я написал это руководство, чтобы обобщить некоторые концептуальные проблемы, с которыми я столкнулся при изучении того, как эффективно использовать git, многие из которых были основаны на ошибочном или неполном понимании того, как git представляет историю изменений. Это то, что я хотел бы прочитать, когда впервые изучал git. Я надеюсь, что это поможет вам!

***

Материалы по теме

Комментарии

ВАКАНСИИ

Добавить вакансию
Разработчик C++
Москва, по итогам собеседования

ЛУЧШИЕ СТАТЬИ ПО ТЕМЕ