3.3 Ветвление в Git — Управление ветками
Теперь, когда вы уже попробовали создавать, объединять и удалять ветки, пора познакомиться с некоторыми инструментами для управления ветками, которые вам пригодятся, когда вы начнёте использовать ветки постоянно.
Команда git branch делает несколько больше, чем просто создаёт и удаляет ветки. При запуске без параметров, вы получите простой список имеющихся у вас веток:
$ git branch iss53 * master testing
Обратите внимание на символ * , стоящий перед веткой master : он указывает на ветку, на которой вы находитесь в настоящий момент (т. е. ветку, на которую указывает HEAD ). Это означает, что если вы сейчас сделаете коммит, ветка master переместится вперёд в соответствии с вашими последними изменениями. Чтобы посмотреть последний коммит на каждой из веток, выполните команду git branch -v :
$ git branch -v iss53 93b412c Fix javascript issue * master 7a98805 Merge branch 'iss53' testing 782fd34 Add scott to the author list in the readme
Опции —merged и —no-merged могут отфильтровать этот список для вывода только тех веток, которые слиты или ещё не слиты в текущую ветку. Чтобы посмотреть те ветки, которые вы уже слили с текущей, можете выполнить команду git branch —merged :
$ git branch --merged iss53 * master
Ветка iss53 присутствует в этом списке потому что вы ранее слили её в master . Те ветки из этого списка, перед которыми нет символа * , можно смело удалять командой git branch -d ; наработки из этих веток уже включены в другую ветку, так что ничего не потеряется.
Чтобы увидеть все ветки, содержащие наработки, которые вы пока ещё не слили в текущую ветку, выполните команду git branch —no-merged :
$ git branch --no-merged testing
Вы увидите оставшуюся ветку. Так как она содержит ещё не слитые наработки, попытка удалить её командой git branch -d приведёт к ошибке:
$ git branch -d testing error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'.
Если вы действительно хотите удалить ветку вместе со всеми наработками, используйте опцию -D , как указано в подсказке.
Если в качестве аргумента не указан коммит или ветка, то опции —merged и —no-merged покажут что уже слито или не слито с вашей текущей веткой соответственно.
Вы всегда можете указать дополнительный аргумент для вывода той же информации, но относительно указанной ветки предварительно не извлекая и не переходя на неё.
$ git checkout testing $ git branch --no-merged master topicA featureB
Переименование ветки
Не переименовывайте ветки, которые всё ещё используются другими участниками. Не переименовывайте ветку в master/main/mainline, не прочитав раздел «Изменение имени главной ветки».
Предположим, у вас есть ветка с именем bad-branch-name , и вы хотите изменить её на corrected-branch-name , сохранив при этом всю историю. Вместе с этим, вы также хотите изменить имя ветки на удалённом сервере (GitHub, GitLab или другой сервер). Как это сделать?
Переименуйте ветку локально с помощью команды git branch —move :
$ git branch --move bad-branch-name corrected-branch-name
Ветка bad-branch-name будет переименована в corrected-branch-name , но это изменение пока только локальное. Чтобы все остальные увидели исправленную ветку в удалённом репозитории, отправьте её туда:
$ git push --set-upstream origin corrected-branch-name
Теперь проверим, где мы сейчас находимся:
$ git branch --all * corrected-branch-name main remotes/origin/bad-branch-name remotes/origin/corrected-branch-name remotes/origin/main
Обратите внимание, что текущая ветка corrected-branch-name , которая также присутствует и на удалённом сервере. Однако, старая ветка всё ещё по-прежнему там, но её можно удалить с помощью команды:
$ git push origin --delete bad-branch-name
Теперь старое имя ветки полностью заменено исправленным.
Изменение имени главной ветки
Предупреждение
Изменение имени ветки, например master/main/mainline/default, сломает интеграции, службы, вспомогательные утилиты и скрипты сборки, которые использует ваш репозиторий. Прежде чем сделать это, обязательно проконсультируйтесь с коллегами. Также убедитесь, что вы выполнили тщательный поиск в своём репозитории и обновили все ссылки на старое имя ветки в вашем коде или скриптах.
Переименуйте локальную ветку master в main с помощью следующей команды:
$ git branch --move master main
После этого, локальной ветки master больше не существует, потому что она была переименована в ветку main .
Чтобы все остальные могли видеть новую ветку main , вам нужно отправить её в общий репозиторий. Это делает переименованную ветку доступной в удалённом репозитории.
$ git push --set-upstream origin main
В итоге, состояние репозитория становится следующим:
$ git branch --all * main remotes/origin/HEAD -> origin/master remotes/origin/main remotes/origin/master
Ваша локальная ветка master исчезла, так как она заменена веткой main . Ветка main доступна в удалённом репозитории. Старая ветка master всё ещё присутствует в удалённом репозитории. Остальные участники будут продолжать использовать ветку master в качестве основы для своей работы, пока вы не совершите ряд дополнительных действий.
Теперь, для завершения перехода на новую ветку перед вами стоят следующие задачи:
- Все проекты, которые зависят от текущего, должны будут обновить свой код и/или конфигурацию.
- Обновите конфигурацию всех запускаемых тестов.
- Исправьте скрипты сборки и публикации артефактов.
- Поправьте настройки репозитория на сервере: задайте новую ветку по умолчанию, обновите правила слияния, а также прочие настройки, которые зависят от имени веток.
- Обновите документацию, исправив ссылки, указывающие на старую ветку.
- Слейте или отмените запросы на слияние изменений, нацеленные на старую ветку.
После того, как вы выполнили все эти задачи и уверены, что ветка main работает так же, как ветка master , вы можете удалить ветку master :
$ git push origin --delete master
Установка веток по умолчанию для git push/git pull
Во время изучения git столкнулся со следующей проблемой: 1) Я могу задать ветку как ветку по умолчанию для git pull с помощью git branch —set-upstream-to remoteRep/remoteBranch находясь на этой ветке. 2) Сделать её веткой «не по умолчанию» для git pull могу с помощью git branch —unset-upstream . 3) Сделать её веткой по умолчанию для git push могу при выполнении git push -u remoteRep remoteBranch 4) А как убрать её статус tracked для git push ? Почему —unset-upstream не убирает ветку для git push ?
git init git remote add tr https://github.com/wcobalt/testrepo.git git pull tr master git remote show tr * внешний репозиторий tr URL для извлечения: https://github.com/wcobalt/testrepo.git URL для отправки: https://github.com/wcobalt/testrepo.git HEAD ветка: master Внешние ветки: b1 отслеживается master отслеживается Локальная ссылка, настроенная для «git push»: master будет отправлена в master (уже актуальна) git branch --unset-upstream fatal: Ветка «master» не имеет информации о вышестоящей ветке
Отслеживать
67.9k 216 216 золотых знаков 77 77 серебряных знаков 219 219 бронзовых знаков
задан 21 окт 2018 в 8:39
1,182 9 9 серебряных знаков 22 22 бронзовых знака
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
команды push и pull делят между собой одну и ту же пару конфигурационных параметров: имя хранилища и имя ветки.
эта пара используется, если не указана явно при выполнении команды.
пример из конфигурационного файла хранилища:
$ grep -A 1 master .git/config [branch "master"] remote = origin merge = refs/heads/master
параметр remote («полное» имя, которое можно использовать для git config — branch.ветка.remote ) — содержит имя хранилища, а параметр merge («полное» имя — branch.ветка.merge ) — содержит имя ветки в этом хранилище.
невозможно для pull и push указать разные ветки (в удалённом хранилище) — нет двух разных параметров (типа merge-для-pull и merge-для-push ).
точно так же невозможно «привязать» ветку (сделать «tracked») по отдельности для push и pull . приведённые вами в пунктах 1 и 3 команды являются синонимами (выдержка из man git-branch ):
git branch (--set-upstream-to= | -u ) []
(технически они добавляют два параметра remote и merge в секцию [branch «ветка»] )
точно так же невозможно «отвязать» ветку (сделать «untracked») по отдельности для push и pull . приведённая вами в пункте 2 команда git branch —unset-upstream [] сделает невозможным вызов (без явного указания хранилища и ветки) как pull , так и push (технически она просто удалит оба параметра remote и merge ).
дополенение по поводу дополнения вопроса, начиная с:
Почему —unset-upstream не убирает ветку для git push ?
вы инициализировали новое хранилище, привязали к нему удалённое хранилище (под именем tr ). ни одна ветка в локальном хранилище пока не связана («tracked») ни с одной удалённой веткой. в чём можно убедиться, как заглянув в .git/conig (ни одной секции [branch «имя»] в нём нет), так и попытавшись выполнить push или pull (без явного указания параметрами имени хранилища и имени ветки).
выполнив команду git pull имя-хранилища имя-ветки , вы получили состояние указанной ветки. но всё ещё ни одна локальная ветка не стала связанной ни с одной удалённой (содержимое .git/config не изменилось).
а раз нет связанной ветки, то нечего и «отвязывать». про что вам и говорит команда branch —unset-upstream :
fatal: Ветка «master» не имеет информации о вышестоящей ветке
3.1 Ветвление в Git — О ветвлении в двух словах
Почти каждая система контроля версий в той или иной форме поддерживает ветвление. Используя ветвление, Вы отклоняетесь от основной линии разработки и продолжаете работу независимо от неё, не вмешиваясь в основную линию. Во многих системах контроля версий создание веток — это очень затратный процесс, часто требующий создания новой копии каталога с исходным кодом, что может занять много времени для большого проекта.
Некоторые люди, говоря о модели ветвления Git, называют её «киллер-фича», что выгодно выделяет Git на фоне остальных систем контроля версий. Что в ней такого особенного? Ветвление Git очень легковесно: операция создания ветки выполняется почти мгновенно, переключение между ветками туда-сюда, обычно, также быстро. В отличие от многих других систем контроля версий, Git поощряет процесс работы, при котором ветвление и слияние выполняется часто, даже по несколько раз в день. Понимание и владение этой функциональностью дает вам уникальный и мощный инструмент, который может полностью изменить привычный процесс разработки.
О ветвлении в двух словах
Для точного понимания механизма ветвлений, необходимо вернуться назад и изучить то, как Git хранит данные.
Как вы можете помнить из Что такое Git?, Git не хранит данные в виде последовательности изменений, он использует набор снимков (snapshot).
Когда вы делаете коммит, Git сохраняет его в виде объекта, который содержит указатель на снимок (snapshot) подготовленных данных. Этот объект так же содержит имя автора и email, сообщение и указатель на коммит или коммиты непосредственно предшествующие данному (его родителей): отсутствие родителя для первоначального коммита, один родитель для обычного коммита, и несколько родителей для результатов слияния двух и более веток.
Предположим, у вас есть каталог с тремя файлами и вы добавляете их все в индекс и создаёте коммит. Во время индексации вычисляется контрольная сумма каждого файла (SHA-1 как мы узнали из Что такое Git?), затем каждый файл сохраняется в репозиторий (Git называет такой файл блоб — большой бинарный объект), а контрольная сумма попадёт в индекс:
$ git add README test.rb LICENSE $ git commit -m 'Initial commit'
Когда вы создаёте коммит командой git commit , Git вычисляет контрольные суммы каждого подкаталога (в нашем случае, только основной каталог проекта) и сохраняет его в репозитории как объект дерева каталогов. Затем Git создаёт объект коммита с метаданными и указателем на основное дерево проекта для возможности воссоздать этот снимок в случае необходимости.
Ваш репозиторий Git теперь хранит пять объектов: три блоб объекта (по одному на каждый файл), объект дерева каталогов, содержащий список файлов и соответствующих им блобов, а так же объект коммита, содержащий метаданные и указатель на объект дерева каталогов.

Рисунок 9. Коммит и его дерево
Если вы сделаете изменения и создадите ещё один коммит, то он будет содержать указатель на предыдущий коммит.

Рисунок 10. Коммит и его родители
Ветка в Git — это простой перемещаемый указатель на один из таких коммитов. По умолчанию, имя основной ветки в Git — master . Как только вы начнёте создавать коммиты, ветка master будет всегда указывать на последний коммит. Каждый раз при создании коммита указатель ветки master будет передвигаться на следующий коммит автоматически.
Примечание
Ветка «master» в Git — это не какая-то особенная ветка. Она точно такая же, как и все остальные ветки. Она существует почти во всех репозиториях только лишь потому, что её создаёт команда git init , а большинство людей не меняют её название.

Рисунок 11. Ветка и история коммитов
Создание новой ветки
Что же на самом деле происходит при создании ветки? Всего лишь создаётся новый указатель для дальнейшего перемещения. Допустим вы хотите создать новую ветку с именем testing . Вы можете это сделать командой git branch :
$ git branch testing
В результате создаётся новый указатель на текущий коммит.

Рисунок 12. Две ветки указывают на одну и ту же последовательность коммитов
Как Git определяет, в какой ветке вы находитесь? Он хранит специальный указатель HEAD . Имейте ввиду, что в Git концепция HEAD значительно отличается от других систем контроля версий, которые вы могли использовать раньше (Subversion или CVS). В Git — это указатель на текущую локальную ветку. В нашем случае мы всё ещё находимся в ветке master . Команда git branch только создаёт новую ветку, но не переключает на неё.

Рисунок 13. HEAD указывает на ветку
Вы можете легко это увидеть при помощи простой команды git log , которая покажет вам куда указывают указатели веток. Эта опция называется —decorate .
$ git log --oneline --decorate f30ab (HEAD -> master, testing) Add feature #32 - ability to add new formats to the central interface 34ac2 Fix bug #1328 - stack overflow under certain conditions 98ca9 Initial commit
Здесь можно увидеть указывающие на коммит f30ab ветки: master и testing .
Переключение веток
Для переключения на существующую ветку выполните команду git checkout . Давайте переключимся на ветку testing :
$ git checkout testing
В результате указатель HEAD переместится на ветку testing .

Рисунок 14. HEAD указывает на текущую ветку
Какой в этом смысл? Давайте сделаем ещё один коммит:
$ vim test.rb $ git commit -a -m 'made a change'

Рисунок 15. Указатель на ветку HEAD переместился вперёд после коммита
Интересная ситуация: указатель на ветку testing переместился вперёд, а master указывает на тот же коммит, где вы были до переключения веток командой git checkout . Давайте переключимся назад на ветку master :
$ git checkout master
Примечание
git log не показывает все ветки по умолчанию
Если выполнить команду git log прямо сейчас, то в её выводе только что созданная ветка «testing» фигурировать не будет.
Ветка никуда не исчезла; просто Git не знает, что именно она вас интересует, и выводит наиболее полезную по его мнению информацию. Другими словами, по умолчанию git log отобразит историю коммитов только для текущей ветки.
Для просмотра истории коммитов другой ветки необходимо явно указать её имя: git log testing Чтобы посмотреть историю по всем веткам — выполните команду с дополнительным флагом: git log —all .

Рисунок 16. HEAD перемещается когда вы делаете checkout
Эта команда сделала две вещи: переместила указатель HEAD назад на ветку master и вернула файлы в рабочем каталоге в то состояние, на снимок которого указывает master . Это также означает, что все вносимые с этого момента изменения будут относиться к старой версии проекта. Другими словами, вы откатили все изменения ветки testing и можете продолжать в другом направлении.
Примечание
Переключение веток меняет файлы в рабочем каталоге
Важно запомнить, что при переключении веток в Git происходит изменение файлов в рабочем каталоге. Если вы переключаетесь на старую ветку, то рабочий каталог будет выглядеть так же, как выглядел на момент последнего коммита в ту ветку. Если Git по каким-то причинам не может этого сделать — он не позволит вам переключиться вообще.
Давайте сделаем ещё несколько изменений и создадим очередной коммит:
$ vim test.rb $ git commit -a -m 'made other changes'
Теперь история вашего проекта разошлась (см Разветвлённая история). Вы создали ветку и переключились на неё, поработали, а затем вернулись в основную ветку и поработали в ней. Эти изменения изолированы друг от друга: вы можете свободно переключаться туда и обратно, а когда понадобится — объединить их. И всё это делается простыми командами: branch , checkout и commit .

Рисунок 17. Разветвлённая история
Все описанные действия можно визуализировать с помощью команды git log . Для отображения истории коммитов, текущего положения указателей веток и истории ветвления выполните команду git log —oneline —decorate —graph —all .
$ git log --oneline --decorate --graph --all * c2b9e (HEAD, master) Made other changes | * 87ab2 (testing) Made a change |/ * f30ab Add feature #32 - ability to add new formats to the central interface * 34ac2 Fix bug #1328 - stack overflow under certain conditions * 98ca9 initial commit of my project
Ветка в Git — это простой файл, содержащий 40 символов контрольной суммы SHA-1 коммита, на который она указывает; поэтому операции с ветками являются дешёвыми с точки зрения потребления ресурсов или времени. Создание новой ветки в Git происходит так же быстро и просто как запись 41 байта в файл (40 знаков и перевод строки).
Это принципиально отличает процесс ветвления в Git от более старых систем контроля версий, где все файлы проекта копируются в другой подкаталог. В зависимости от размера проекта, операции ветвления в таких системах могут занимать секунды или даже минуты, когда в Git эти операции мгновенны. Поскольку при коммите мы сохраняем указатель на родительский коммит, то поиск подходящей базы для слияния веток делается автоматически и, в большинстве случаев, очень прост. Эти возможности побуждают разработчиков чаще создавать и использовать ветки.
Давайте посмотрим, почему и вам имеет смысл делать так же.
Примечание
Одновременное создание новой ветки и переключение на неё
Как правило, при создании новой ветки вы хотите сразу на неё переключиться — это можно сделать используя команду git checkout -b .
Примечание
Начиная с Git версии 2.23, вы можете использовать git switch вместо git checkout , чтобы:
- Переключиться на существующую ветку: git switch testing-branch .
- Создать новую ветку и переключиться на неё: git switch -c new-branch . Флаг -c означает создание, но также можно использовать полный формат:` —create`.
- Вернуться к предыдущей извлечённой ветке: git switch — .
Изменение ветви по умолчанию
Если в репозитории есть несколько ветвей, можно настроить любую ветвь как ветвь по умолчанию.
Кто может использовать эту функцию.
People with admin access for a repository can change the default branch for the repository.
About changing the default branch
You can choose the default branch for a repository. The default branch is the base branch for pull requests and code commits. For more information about the default branch, see «About branches.»
Note: If you use the Git-Subversion bridge, changing the default branch will affect your trunk branch contents and the HEAD you see when you list references for the remote repository. For more information, see «Support for Subversion clients» and git-ls-remote in the Git documentation.
You can also rename the default branch. For more information, see «Renaming a branch.»
Prerequisites
To change the default branch, your repository must have more than one branch. For more information, see «Creating and deleting branches within your repository.»
Additionally, you need to have admin access to a repository to change the default branch.
Changing the default branch
- On GitHub.com, navigate to the main page of the repository.
- Under your repository name, click
Settings. If you cannot see the «Settings» tab, select the

dropdown menu, then click Settings.