Руководство по merge, rebase, squash и cherry-pick

Источник: «Beyond the Basics. Guide to Deeply Understand Merge, Rebase, Squash, and Cherry Pick - When to Use Them With Real-World Examples»
Эта статья — просто сборник материалов и реальных примеров, которые я бы с удовольствием прочитал, когда изучал Git. Это сделало бы процесс обучения более насыщенным, предоставив больше информации не только о том, как, но и когда следует использовать эти команды.

Введение

Git — мощный инструмент, помогающий разработчикам совместно работать над программными проектами. Созданный Линусом Торвальдсом в 2005 году, он стал одной из самых распространённых систем контроля версий в индустрии разработки программного обеспечения.

Если вы новичок в Git, может показаться сложным найти информацию о том, когда и как использовать определённые команды с реальными примерами. Многие руководства рассказывают только о командах, чего может быть достаточно для опытных разработчиков, но не для новичков.

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

В статье рассмотрим основные команды Git, позволяющие эффективно объединять ветви и реагировать на различные ситуации. Рассмотрим основные различия между merge и rebase, а также то, когда следует использовать каждую из них. Также рассмотрим, как использовать cherry pick для добавления определённых коммитов в одну или несколько ветвей, и почему следует объединять связанные коммиты в один, для сохранения чистоты ветви. Наконец, обсудим, как предотвратить некоторые распространённые проблемы при работе с ветвями.

Что лучше использовать, merge или rebase

Выбор между merge (слиянием) и rebase (перебазированием) может быть непростым и обычно зависит от практики вашей компании. Если у вас есть выбор, знание плюсов и минусов каждого метода очень важно для принятия правильного решения, основанного на потребностях вашей компании.

Git merge объединяет изменения из одной ветви в другую, создавая новый коммит с объединёнными изменениями. С другой стороны, Git rebase переписывает историю одной ветви на другую, добавляя ваши коммиты поверх обновлённой ветви. Проще говоря, он временно удаляет ваши коммиты, обновляет ветвь с указанной, а затем добавляет ваши коммиты в начало истории.

Теперь рассмотрим каждый метод более подробно.

Рассмотрим ветвь main со следующей историей коммитов:

git checkout main
git log --oneline
0a9c4e8 (HEAD -> main) feature3
26c4d90 feature2
8bb8ce9 feature1

Коды в начале каждой строки называются хэшами коммитов или ID коммитов, и служат уникальными идентификаторами, связанными с каждым созданным коммитом. ID коммита состоит из 40-значного SHA-хэша (алгоритм хэширования), который может быть сокращён до более короткой 7-значной версии.

Продолжая пример, у вас есть назначенный тикет, и необходимо создать ветвь feature4 с помощью git branch feature4 и git checkout feature4. Вы разработали свою функцию, добавили тесты, и теперь она готова к слиянию с main. У неё следующая история коммитов:

git checkout feature4
git log --oneline
dd01e58 (HEAD -> feature4) (fix) feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Поэтому заходите на Github и создаёте новый Pull Request, но обнаруживаете, что ветвь main была обновлена, пока шла работа над вашей ветвью. Другими словами, ветвь main теперь отличается от той, в которой вы создали свою ветвь. В ней появился новый коммит.

git checkout main
git pull origin main
git log --oneline
cf0e10a (HEAD -> main) feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Однако конфликты могут возникать, когда в целевой ветви появляются новые коммиты, изменяющие те же участки, над которыми вы работали в своей ветви. В таких случаях у есть альтернатива: вместо слияния feature4 с main (main ← feature4), можно обновить feature4 изменениями из main (main → feature4). Для этого у вас есть две опции: merge (слияние) или rebase (перебазирование).

Подход merge (слияние)

Если вы выполните слияние main с feature4, то Git создаст новый коммит, содержащий изменения из main, и добавит их на вершину рабочего дерева. Давайте посмотрим на это в действии.

git checkout feature4
git merge main

Git откроет настроенный вами редактор, которым по умолчанию является Vim. Вы увидите что-то вроде этого:

Merge branch 'main' into feature4
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.

Для простоты я оставлю это сообщение коммита по умолчанию. Чтобы его сохранить, нажмите ESC, введите :wq, затем Enter. Если вы не знакомы с командами Vim, посмотрите краткий учебник на YouTube или на другой предпочитаемой вами платформе.

Теперь снова проверьте историю коммитов:

git log --oneline
96f49c0 (HEAD -> feature4) Merge branch 'main' into feature4
cf0e10a (main) feature5
dd01e58 (fix) feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Обратите внимание, что есть два новых коммита, но cf0e10a — единственный, который был в main. Откуда взялся этот другой коммит?

Когда происходит слияние ветви, Git добавляет коммиты из исходной ветви и создаёт новый коммит, объединяющий изменения из обеих ветвей. Если конфликтов нет, этот коммит будет создан автоматически. Однако если конфликты возникли, их необходимо разрешить, а затем вручную создать коммит.

Не забудьте обновить локальную ветвь main перед слиянием. Если этого не сделать, то сливать в feature4 будет нечего.

Теперь можно отправить изменения с помощью git push origin feature4, а затем слить их в main. Для простоты давайте сделаем локальное git слияние с main:

git checkout main
git merge feature4
git log --oneline
96f49c0 (HEAD -> main, feature4) Merge branch 'main' into feature4
cf0e10a feature5
dd01e58 (fix) feature4
55b4a8b feature4
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Обратите внимание на это (HEAD -> main, feature4). Это означает, что main и feature4 теперь имеют один и тот же коммит в HEAD. Другими словами, обе ветви указывают на один и тот же коммит.

Подход rebase (перебазирование)

Как уже говорилось, rebase (перебазирование) немного отличается. По сути, он переписывает историю ветви, добавляя ваши коммиты поверх обновлённой ветви. Но что означает переписать в данном контексте? Это значит изменить оригинальную историю коммитов, создав новые коммиты с другими хэшами, и добавить их в историю коммитов, но не обязательно на самый верх. После этого старая история коммитов заменяется новой. Давайте рассмотрим это на примере:

git checkout main
git pull origin main
git checkout feature4
git rebase main
git log --oneline
0c847bd (HEAD -> feature4) (fix) feature4
b86b56d feature4
cf0e10a (main) feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Как видите, cf0e10a был добавлен до ваших коммитов, а этот коммит был создан после коммитов из feature4. С помощью Git rebase ваши изменения добавляются в начало истории без дополнительных коммитов, как при слиянии. Однако можно заметить, что хэши двух ваших коммитов из feature4 не такие, как раньше, а коммиты из main остались неизменными. Странно, правда?

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

Теперь, когда feature4 обновлена, можно выполнить обычное слияние с main. Помните, что в реальной жизни нужно будет опубликовать изменения и создать Pull Request.

> git checkout main
> git merge feature4
> git log --oneline
0c847bd (HEAD -> main, feature4) (fix) feature4
b86b56d feature4
cf0e10a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

На этот раз хэши коммитов обеих ветвей идентичны, и лишних коммитов нет. Однако стоит отметить, что Git может вести себя по-другому на таких платформах, как GitLab и GitHub, где могут быть добавлены дополнительные коммиты.

Моя рекомендация — не использовать rebase в main или других критических ветвях, чтобы сохранить исходные хэши для лучшей отслеживаемости. Вместо этого используйте его для временных ветвей, полученных из другой ветви, например, ветви feature. Если ваша ветвь будет удалена после слияния, то вы можете её перебазировать. Для main это не так. После того как коммиты были добавлены в main, вы не должны их изменять.

Кроме того, rebase не даст длинным сериям коммитов оказаться разбросанными в истории коммитов и вызвать шум в вашей ветви.

Невозможно запушить изменения после rebase

В реальных условиях вы не будете сливать в main напрямую. На самом деле, скорее всего, вы не сможете слить изменения в ветвь main на GitHub. Вместо этого необходимо создать Pull Request (или Merge Request, если используется GitLab), чтобы получить возможность слить изменения. Если предположить, что вы уже создали свою ветвь и разместили её в удалённом репозитории, то, когда соберётесь отправить изменения с помощью git push origin <branch>, можете получить ошибку, похожую на эту:

Your branch and 'origin/<branch>' have diverged,
...
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean

Если принудительно выполнить git pull, можно потерять свои изменения. Проблему можно решить, выполнив следующую команду: git push -f origin <branch>. Имейте в виду, что git push -f переопределит ветвь upstream, поэтому будьте с этим осторожны. Позже мы рассмотрим способы предотвращения потери информации.

Cherry pick

Представьте, что работаете в компании, где в разработке находятся три разных ветви: main, legacy-v1 и legacy-v2. Соглашение об именовании ветвей дано в образовательных целях.

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

Следующее логичное решение, приходящее на ум, — создать новый Pull Request для слияния этих изменений с другими ветвями. Однако возникает проблема: две другие ветви могут значительно отличаться от ветви main, что приведёт к многочисленным конфликтам. В таких случаях их чистое слияние может оказаться невозможным. Вот тут-то и приходит на помощь cherry-pick.

Эта команда позволяет добавлять произвольные коммиты из ветви в HEAD другой ветви без необходимости полного слияния.

Синтаксис выглядит следующим образом:

git cherry-pick <commit-sha>

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

> git log --oneline
8d84e7b (HEAD -> main) (fix) feature 1
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1

Предположим, что 8d84e7b (краткая версия) или 8d84e7b6bf5ed8a4fee96dfa820e544567542785 — хэш коммита, который необходимо перенести в две другие ветви.

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

git checkout legacy-v1
git cherry-pick 8d84e7b6bf5ed8a4fee96dfa820e544567542785

Коммит успешно добавлен.

git log --oneline
0c41007 (HEAD -> legacy-v1) (fix) feature 1
9689a1c feature 5
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1

Повторите процесс для legacy-v2.

git checkout legacy-v2
git cherry-pick 8d84e7b6bf5ed8a4fee96dfa820e544567542785
git log --oneline
73deb0b (HEAD -> legacy-v2) (fix) feature 1
0b67041 feature 6
222159b feature 4
32d540d feature 3
718f740 feature 2
78662d0 feature 1

Обратите внимание, что хэши коммитов legacy-v1 и legacy-v2 отличаются от main. Это связано с тем, что во время cherry-pick Git создал новый коммит с 8d84e7b и добавил его в целевую ветвь.

Считается ли Cherry Pick плохой практикой

Некоторые разработчики, особенно самые пуританские пользователи Git, не рекомендуют использовать эту команду. Они предпочтут merge (слияние), а не cherry-pick. Но, возможно, они считают, что команда cherry-pick плоха не сама по себе, а то, как вы её используете, может навредить вашему репозиторию.

Мне нравится комментарий, опубликованный на вопрос StackOverflow:

Идентификатор SHA1 коммита определяет его не только сам по себе, но и по отношению ко всем другим коммитам, предшествующим ему. Это даёт гарантию того, что состояние репозитория при данном SHA1 идентично во всех клонах. Теоретически нет никаких шансов, что кто-то сделал то, что выглядит как одно и то же изменение, но на самом деле повредил или захватил ваш репозиторий. Вы можете cherry-pick (выбрать) отдельные изменения, и они, скорее всего, будут одинаковыми, но нет гарантии. (В качестве небольшой второстепенной проблемы можно отметить, что новые коммиты с cherry-pick будут занимать дополнительное место, если кто-то ещё раз выполнит cherry-pick в том же коммите, так как они оба будут присутствовать в истории, даже если ваши рабочие копии в итоге окажутся идентичными).

(Git Cherry-pick vs Merge Workflow, 2017)

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

Однако нужно быть очень осторожным, если ваш коммит сложный, изменяет разные файлы и вызывает конфликты слияния. Рекомендуется иметь хорошее покрытие тестами, которое поможет быстро обнаружить, если что-то сломалось.

Git squash

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

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

b86b56d Add initial HTML structure for payment checkout page.
a5e392f Implement basic CSS styles for payment form.
cf872e2 Fix alignment issues in the payment summary section.
0c31e2d Add credit card input validation for card number and expiration date.
d6c59a7 Implement UI for selecting payment method (credit card, PayPal, etc.).
e8af221 Add CSS transitions for a smoother payment form experience.
3e987b8 Fix bug with PayPal payment option not showing up in the UI.
95c67f2 Update button styles for the payment confirmation step.
713bd64 Integrate backend API for processing payment requests.
2d344ef Update success message for completed payments.

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

b86b56d Implement new payment checkout UI with improved user experience, payment method selection, validation, and backend integration.

Это звучит лучше, верно? Очень часто компании стараются делать один коммит на каждую фичу в ветви main, потому что так проще сделать откат, если что-то пошло не так, или добавить теги в новые релизы.

Рассмотрим ещё один пример.

Есть две ветви: main и feature4. Ниже приведена история обеих ветвей:

git log --oneline
git checkout main
d303a7a (HEAD -> main) feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
git checkout feature4
git log --oneline
0c847bd (HEAD -> feature4) (fix) feature4
b86b56d feature4
d303a7a (main) feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

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

Возможно, сообщения этих коммитов не имеют значения в общей картине продукта. Единственное, что имеет значение, — это то, что feature4 готова к слиянию с main. Для удаления этих коммитов можно использовать rebase или merge.

Эти две ветви имеют следующую историю коммитов:

git checkout main
git log --oneline
159678e (HEAD -> main) feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1
git checkout feature4
0c847bd (HEAD -> feature4) (fix) feature4
b86b56d feature4
d303a7a (main) feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Squash со слиянием

Эта команда очень похожа на традиционный процесс слияния. Единственное отличие заключается в том, что можно добавить флаг -squash. Это добавит изменения из feature4 в индекс (эквивалентно тому, как если бы просто написали все изменения и выполнили git add). Затем нужно закоммитить изменения с осмысленным именем, чтобы завершить процесс слияния. Смотрите пример ниже:

git checkout main
git merge --squash feature4
git commit -m "feature4"

Если возникают конфликты слияния, их нужно решить до выполнения коммита.

После слияния новый коммит, содержащий два других коммита, будет создан следующим образом:

git log --oneline
cda90a7 (HEAD -> main) feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Обратите внимание, что этот коммит был добавлен после feature6, хотя он был добавлен после последнего коммита feature4.

Squash с перебазированием

Для этого в rebase нужно добавить флаг -i, как показано ниже:

git checkout feature4
git rebase -i main

Git откроет Vim. Вы увидите что-то похожее на это:

pick b86b56d feature4
pick 0c847bd (fix) feature4

# Rebase 159678e..0c847bd onto 159678e (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
# commit's log message, unless -C is used, in which case
# keep only this commit's message; -c is same as -C but
# opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# create a merge commit using the original merge commit's
# message (or the oneline, if no original merge commit was
# specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
# to this position in the new commits. The <ref> is
# updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#

Не паникуйте. Все строки, начинающиеся с #, — это просто указания, что можно делать с помощью этой утилиты. Для нас сейчас важна только опция squash, или её аббревиатура s. Вам нужно заменить слово "pick", начиная со второго сверху, следующим образом:

pick b86b56d feature4
squash 0c847bd (fix) feature4

Все строки со squash будут объединены с предыдущей, в которой есть слово pick.

Чтобы сохранить изменения, нажмите ESC, введите :wq, затем Enter. Git снова откроет Vim, но уже с запросом сообщения коммита.

# This is a combination of 2 commits.
# This is the 1st commit message:

feature4

# This is the commit message #2:

(fix) feature4

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# Date: Sat Jul 15 09:11:55 2023 -0600
#
# interactive rebase in progress; onto 159678e
# Last commands done (2 commands done):
# pick b86b56d feature4
# squash 0c847bd (fix) feature4
# No commands remaining.
# You are currently rebasing branch 'feature4' on '159678e'.
#
# Changes to be committed:
# new file: file2.txt
#

Добавьте осмысленное имя. В данном случае, для целей этого руководства, достаточно feature4. Можно удалить все строки, нажав dd или d<количество удаляемых строк>d (или удалить всё от строки в которой размещён курсор до конца файла dG).

После этого снова нажмите ESC, введите :wq, затем Enter, чтобы сохранить изменения. (Если не входили в режим редактирования, а оставались в командном режиме, то ESC нажимать не нужно. Просто введите команду :wq и нажмите Enter)

git log --oneline
62b8724 (HEAD -> feature4) feature4
159678e (main) feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

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

Это происходит потому, что Git не может повторно использовать хэш-код, содержащий разные изменения. В этом случае Git вынужден использовать другой хэш и сохранять все изменения как новый коммит. Требуя первоначальной коммит "pick", Git устанавливает чёткую точку отсчёта для операции rebase. Это гарантирует, что rebase будет проходить организованно и предсказуемо, без каких-либо двусмысленностей относительно порядка коммитов.

Теперь можно переключиться на main и выполнить обычное слияние следующим образом:

git checkout main
git merge feature4
git log --oneline
62b8724 (HEAD -> main, feature4) feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Поскольку это обычное слияние, коммит 62b8724 был сохранён. Это также означает, что main и feature4 теперь указывают на один и тот же коммит.

Что произойдёт, если испортить ветвь при перебазировании или слиянии

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

git checkout main
git branch -D feature4 # удаление ветви feature4
git checkout origin feature4

Ещё одна альтернатива — резервное копирование ветвей, которые будут затронуты, перед выполнением рискованных команд. Продолжая предыдущий пример, можно создать резервные копии ветвей main и feature4 перед любой операцией, способной необратимо повлиять на них.

Этот вариант предпочтителен, если планируется перенести изменения в удалённый репозиторий, потому что если выполнить git push -f origin <branch>, вы переопределите удалённые ветви и можете потерять информацию, если не знаете, что делаете. Резервное копирование ветвей выполняется очень просто и может избавить от головной боли:

git branch feature4-backup feature4

Таким образом, если вы удалите или случайно повредите локальную и удалённую ветви, то сможете восстановить ветвь, выполнив эту команду:

git branch feature4 feature4-backup
git push --set-upstream origin feature4

Третья альтернатива — сохранять хэш коммита вместо резервного копирования всей ветви. В силу особенностей Git'а можно получить доступ к коммитам по хэшу, даже если удалить ветвь, к которой они относились. Рассмотрим ветвь feature8 со следующими коммитами:

git checkout feature8
git log --oneline
407f3e2 (HEAD -> feature8) feature8
309129e (fix) feature7
9ec402e feature7
62b8724 feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Вы можете сохранить эти коммиты в файле (имеется ввиду хэши коммитов), к которому сможете обратиться позже. Таким образом, если вы удалите свою ветвь, то сможете восстановиться из коммита. Представьте, что случайно удалили несколько коммитов с помощью этой команды:

git reset --hard HEAD~3
git push -f origin feature8

Теперь лог выглядит следующим образом:

62b8724 (HEAD -> feature8) feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

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

git checkout feature8
git merge 407f3e2

Теперь история коммитов восстановлена.

git log --oneline
407f3e2 (HEAD -> main) feature8
309129e (fix) feature7
9ec402e feature7
62b8724 feature4
159678e feature6
d303a7a feature5
0a9c4e8 feature3
26c4d90 feature2
8bb8ce9 feature1

Не забывайте, что изменения, внесённые в удалённый репозиторий, должны быть исправлены и в удалённой ветви.

Заключение

В статье мы рассмотрели основные команды Git и их практическое применение. Фундаментальные различия между merge, rebase, cherry-pick и squash.

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

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

Библиография

Комментарии


Дополнительные материалы

Предыдущая Статья

Что означает гидратация

Следующая Статья

Оптимизация обработки больших массивов данных с Lazy Collection