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

git branchПолучить список, создание или удаление ветвей.
Документация здесь.
Команды:
git branch <имя ветки> — создаёт новую ветку с HEAD, указывающим на HEAD. Если не передать аргумент <имя ветки>, то команда выведет список всех локальных веток;
git checkout <имя ветки> — переключается на эту ветку. Можно передать опцию -b, чтобы создать новую ветку перед переключением;
git branch -d <имя ветки> — удаляет ветку.
Пример выполнения этих команд:

Локальный и удалённый репозитории могут иметь немало ветвей, поэтому когда вы отслеживаете удалённый репозиторий — отслеживается удалённая ветка (git clone привязывает вашу ветку main или master к ветке origin/main или origin/master удалённого репозитория).
Привязка к удалённой ветке:
git branch -u <имя удалённого репозитория>/<удалённая ветка>— привязывает текущую ветку к указанной удалённой в етке;git checkout --track <имя удалённого репозитория>/<удалённая ветка>— аналог предыдущей команды;git checkout -b <ветка> <имя удалённого репозитория>/<удалённая ветка>— создаёт новую локальную ветку и начинает отслеживать удалённую;git branch --vv— показывает локальные и отслеживаемые удалённые ветки;git checkout <удалённая ветка>— создаёт локальную ветку с таким же именем, как у удалённой, и начинает её отслеживать.
В общем, git checkout связан с изменением места, на которое указывает HEAD ветки, что похоже на то, как git reset перемещает общий HEAD.
Прятки и чистка
Есть одна тонкость — при переключении веток Git требует, чтобы рабочее состояние было чистым, то есть все изменения в отслеживаемых файлах должны быть зафиксированы. При некоторых обстоятельствах Git может автоматически перенести незафиксированное изменение в другую ветку.
git stashСкрыть изменения в "грязном рабочем" каталоге.
Документация здесь.
Однако порой у вас есть незавершённые изменения, которые нельзя фиксировать. В такой ситуации их можно сохранить и "спрятать" с помощью команды git stash.
Пример выполнения git stash:

Чтобы вернуть изменения, используйте git stash apply.
Возможно, вместо этого вы захотите стереть все спрятанные изменения. В таком случае используйте команду git stash clear.
Слияние
Дадим определения:
- Сливаемая ветка – та ветка, с которой мы берем изменения, чтобы влить их в целевую.
- Целевая ветка – та ветка, в которую мы сливаем наши изменения.
- Слияние веток – это перенос изменений с одной ветки на другую. При этом слияние не затрагивает сливаемую ветку, то есть она остается в том же состоянии, что позволяет нам потом продолжить работу с ней.
Слияние включает в себя создание нового коммита, который основан на общем коммите-предке двух ветвей и указывает на оба HEAD в качестве предыдущих коммитов.
Пример слияния (источник: tproger.ru):

git mergeСливает изменения с переданной ветки в текущую.
Документация здесь.
Для слияния мы переходим на основную ветку и используем команду git merge <тематическая ветка>.
Если обе ветви меняют одну и ту же часть файла, то возникает конфликт слияния — ситуация, в которой Git не знает, какую версию файла сохранить, поэтому разрешать конфликт нужно собственноручно. Чтобы увидеть конфликтующие файлы, используйте git status.
Пример с двумя ветками, в которых изменен один и тот же файл:

Переходим в ветку main через git checkout main и делаем git merge new-branch.
Статус репозитория:

git status показывает:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README
no changes added to commit (use "git add" and/or "git commit -a")
После открытия таких файлов вы увидите похожие маркеры разрешения конфликта:

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

git rebaseПовторное применение коммитов поверх другого базового "конца".
Документация здесь.
Для перемещения используется команда git rebase <основная ветка> <тематическая ветка>, которая воспроизводит изменения тематической ветки на основной; HEAD тематической ветки указывает на последний воспроизведённый коммит.
Перемещение vs. слияние
После слияния лог с историей может выглядеть довольно беспорядочно. С другой стороны, перемещение позволяет переписать историю в нормальной, последовательной форме. Но перемещение — не панацея от запутанных логов: перемещённые коммиты отличаются от оригинальных, хотя и имеют одного и того же автора, сообщение и изменения.
Сценарий:
- В своей ветке вы создаёте несколько коммитов и сливаете их в мастер-ветку.
- Кто-то ещё решает поработать на основе ваших коммитов.
- Вы решаете переместить ваши коммиты и отправить их на сервер.
- Когда кто-то попытается слить свою работу на основе ваших изначальных коммитов, в итоге мы получим две параллельные ветки с одним автором, сообщениями и изменениями, но разными коммитами.
- Перемещайте изменения только на вашей приватной локальной ветке — не перемещайте коммиты, от которых зависит ещё кто-то.
Откат коммитов — revert и reset
git revertОтменить некоторые существующие коммиты.
Документация здесь.
git resetСброс текущей HEAD в указанное состояние.
Документация здесь.
Похожие дебаты по поводу того, что лучше использовать, возникают, когда вы хотите откатить коммит. Команда git revert <коммит> создаёт новый коммит, отменяющий изменения, но сохраняющи й историю, в то время как git reset <коммит> перемещает указатель HEAD, предоставляя более чистую историю (словно бы этого коммита никогда и не было). Важно отметить, что это также означает, что вы больше не сможете вернуться обратно к этим изменениям, например, если вы всё-таки решите, что отмена коммита была лишней. Чище — не значит лучше!
Атрибуция
При подготовке статьи использован материал: