|
|||||||
Git: как переключиться на нужный коммит и вернуться обратно? Понимание, что такое ветка
Время создания: 22.06.2014 15:41
Автор: Xintrea
Текстовые метки: git, commit, коммит, checkout, переключиться, перейти, вернуться, head, ошибка, ветка, понимание, объяснение
Раздел: Компьютер - Программирование - Системы контроля версий (VCS) - Git
Запись: xintrea/mytetra_syncro/master/base/1403437294hkfzh1wflf/text.html на raw.github.com
|
|||||||
|
|||||||
Как переключиться на нужный коммит? Для переключения на нужный коммит используется действие checkout. После переключения, все файлы в проекте станут такими, какими они были в данном коммите. Переключение на коммит происходит командой: git checkout commit Где commit - это хеш (обозначение, имя) коммита, причем можно указывать не весь хеш, а несколько начальных символов хеша. Примечание: переключение на интересующий пользователя коммит всегда будет приводить репозитарий в состояние detached HEAD. Это нормально, не стоит этого бояться. Нахождение в состоянии "detached HEAD" можно проверить командой git status: $ git checkout 3c53ec44 ... $ git status HEAD отделён на 3c53ec44 Состояние "detached HEAD" означает, что текущий рабочий указатель не находится ни на какой ветке. Но как же так? Ведь коммит всегда принадлежит какой-то ветке! Это можно увидеть в том же gitk... А разгадка в том, что коммиты в Git - это, конечно, "снимки состояния репозитария, которые связаны между собой, образуя цепочки". Но нужно понимать, что цепочки коммитов в Git не считаются ветками! Вот это поворот! Как работают ветки в Git? Веткой в Git называется указатель на коммит, и этому указателю задано определенное имя. Если такой указатель указывает на последний коммит в цепочке, то в момент добавления нового коммита (у которого текущий является родителем) этот именованный указатель автоматически "переместится": то есть он начнет указывать на новый коммит. А имя указателя останется прежним. Таким образом, создается иллюзия, что программист работает в именованной ветке, и при добавлении коммитов ветка прирастает новыми коммитами. Хотя, на деле, система Git оперирует не ветками, а именно указателями на коммиты, не более того. Нужно запомнить: никаких веток, в естественном человеческом понимании, в Git нет. Вышеуказанные размышления можно продемонстрировать и по-другому. Нахождение в состоянии "detached HEAD" можно проверить командой git branch: $ git branch * (HEAD отделён на 3c53ec44) control_panel master new_engine Здесь видно, что пользователь переключился на какой-то коммит в истории. Но не видно на какой ветке находится пользователь, и, тем более, не видно на какой ветке он находился ранее. (Перед переключением, в gitk, было видно, что коммит 3c53ec44 находится в ветке control_panel, но не является в ней последним). А так как коммит не самый последний в ветке, то после переключения рабочий указатель не начинает указывать ни на какую ветку (то есть рабочий указатель не совпадает с каким-либо именованным указателем, находящимся на конце какой-либо ветки). А такое состояние, на первый взгляд, и считается "detached HEAD". Но тогда возникает вопрос: а что произойдет, если с помощью хеша коммита переключиться на коммит, который является последним в какой-нибудь цепочке, и в gitk видно, что на данном коммите завершается ветка control_panel? Поймет ли Git, что произошло переключение на коммит, на который указывает именованный указатель с именем control_panel? То есть, поймет ли Git, что происходит переключение на ветку control_panel? Следующие команды показывают, что произошло переключение на коммит, на который так же указывает указатель ветки control_panel. И видно, что хеш коммита (на который переключились) 4c171d82 и хеш ветки 4c171d82 - совпадают. Но состояние "detached HEAD" все равно возникло: $ git checkout 4c171d82 $ git branch -v * (HEAD отделён на 4c171d82) 4c171d82 Manager и регулятор громкости control_panel 4c171d82 Manager и регулятор громкости master c4bfddfd ALS перенесен в разел коммутаторов new_engine b9bcf376 Merge branch 'new_engine' of ... То есть, даже если пользователь переключился на конечный коммит какой-либо ветки, состояние считается все равно как "detached HEAD". Надо разобраться почему так происходит. А дело вот в чем. В Git есть два указателя:
Так вот, надо знать что:
Если WT-указатель и HEAD-указатель не совпадают, такое состояние и называется "detached HEAD". А когда они совпадают - значит можно нормально работать. Причем работа будет проиcходить в ветке, имя которой соответствует именованному указателю на коммит, на который так же указывает HEAD. Важно для понимания: возможно ли в Git ветвление без веток? Да, если над проектом работает несколько человек, или если один человек работает над проектом из разных локаций (на работе, дома, в дороге), или при различных комбинациях такой организации работы. Во всех этих случаях, даже в пределах одной ветки, могут образовываться различные ветвления. Например, если человек делал несколько коммитов, находясь в дороге (и у него небыло интернета), то после того как интернет появится, эти коммиты заливаются на сервер, и они видны как одна цепочка коммитов. А другая цепочка коммитов, которые делались другими сотрудниками в этой ветке, пока человек был в дороге, будет тоже видна в этой же ветке. И выглядеть эти две цепочки будут в логе как две цепочки, которые разветвились в момент, когда человек поехал в командировку. И самое главное, что эти две цепочки не являются отдельными ветками. Это просто цепочки коммитов, различным образом разветвляющиеся и сливающиеся. Дописать... А как вернуться обратно после просмотра коммита? Ответ. Можно воспользоваться командой: git checkout - (да, в конце команды ставится символ тире "-") Эта команда вернет состояние репозитария в ту точку, где пользователь Git был до перехода. Даже если переход производился на коммит в другой ветке, возврат будет происходить с перепрыгиванием на ту ветку, где пользователь находился изначально. Внимание! Данная команда производит переключение только между двумя коммитами, назовем их 1 и 2. При переходе с 1 на 2, git помнит что переход был сделан, с коммита 1. И команда git checkout - переместит пользователя обратно с коммита 2 на "запомненный" 1. Но в момент этого переключения git начнет помнить, что переключение производилось с коммита 2. И при очередной команде git checkout - снова произойдет переключение на коммит 2. И так по циклу. Другими словами это значит, что команда git checkout - не возвращает пользователя по шагам по переключенным коммитам. Она способна вернуть пользователя только на один предыдущий коммит, а дальше она "зацикливается". Вообще, в Git нет прямой команды, которая покажет список всех коммитов, на которые переключался пользователь. Однако, Git хранит информацию о последовательном изменений состояния указателя HEAD, что по своей сути и означает те места (коммиты/ветки/состояния) на которые переключался пользователь. Чтобы посмотреть эту информацию, используется команда: git reflog Команда git reflog отображает список всех изменений, которые происходили с HEAD, например:
Вот как выглядит вывод этой команды: 9ea9d6278 (HEAD) HEAD@{22}: checkout: moving from 05bfb81ab to 9ea9d6278 05bfb81ab (tag: v20.08.3, origin/release/20.08) HEAD@{23}: checkout: moving from 9fa8c11d1 to v20.08.3 9fa8c11d1 (tag: v18.04.0) HEAD@{24}: checkout: moving from 05bfb81ab to v18.04.0 05bfb81ab (tag: v20.08.3, origin/release/20.08) HEAD@{25}: checkout: moving from master to v20.08.3 83186b7ba (origin/master, origin/HEAD, master) HEAD@{26}: clone: from https://invent.kde.org/utilities/konsole.git Самое "старое" состояние написано внизу вывода, более свежие - ближе к верху списка. В начале каждой строки написан хеш коммита, переключившись на который пользователь попадет в нужно место, где он находился. У команды git reflog есть ограничения. Git хранит историю переключений в reflog только определённое время. По умолчанию, это:
Если необходимо, эти значения можно изменить в конфигурации Git. А как перейти в самое свежее состояние? Дописать. Свежее состояние - внутри ветки? |
|||||||
Так же в этом разделе:
|
|||||||
![]() |
|||||||
|
|||||||
|