Помогал на днях одному парню с git[1] и наткнулся на неочевидную вещь: команды `git checkout branchname` и `git checkout abcde`, где `abcde` — самый свежий коммит (далее — голова) ветки `branchname`, *не эквивалентны*. Если после первой команды сделать коммит, он попадёт в `branchname` (станет её головой); если же сделать коммит после второй команды, `branchname` всё так же будет указывать на `abcde`.
Ларчик открывается довольно просто. `git checkout` просто заставляет `HEAD` указывать туда, куда я сказал. Если сказать `git checkout branchname`, `HEAD` будет указывать на `branchname`, который, в свою очередь, указывает на `abcde`. Тогда при `git commit` мы обновим ветку `branchname` (которая, если кто не в курсе, просто указатель на некий коммит — голову ветки), не задевая `HEAD`.
Если же сделать `git checkout abcde`, мы переходим в detached head state, то есть `HEAD` теперь указывает не на ветку, а на коммит. Если теперь сделать `git commit`, мы обновим непосредственно `HEAD`, не задевая `branchname`. Свежесозданный коммит не принадлежит ни одной ветке, так что если мы сделаем `git checkout someotherbranch`, он будет почти что потерян (см. git-reflog(1) и git-gc(1)).
Жаль, что объяснение вышло таким сумбурным, но я действительно не знаю, как написать лучше.
1. http://juick.com/k0st1x/2083845
Minoru
03.10.2012 12:11 antaeus
Do you really want to delete ?