Предпосылка вашего вопроса неверна:
Простое git checkout <argument>
невозможно, потому что оно не проверяет удаленную ветвь так, как git checkout origin/<argument>
.
Здесь важно понять несколько взаимосвязанных вещей о Git:
- Всегда есть - ну, почти всегда - текущий коммит, который вы можете использовать как слово
HEAD
find. - Не всегда существует текущая ветвь, но если она есть, это имя ветки , то есть ссылка, полное имя которой имеет вид
refs/heads/<em>name</em>
.Одно и то же слово - HEAD
, заглавными буквами, находит название этой ветви.Если не является текущим именем ветви, Git называет это отсоединенным HEAD . - A именем удаленного отслеживания , таким как
origin/master
, это не имя ветви .Его полная форма начинается с refs/remotes/
, а не refs/heads/
. - Если вы скажете
git checkout
проверить коммит, но идентифицируете его чем-то отличным от branch name, Gitбудет - если проверка прошла успешно, то есть - создаст состояние detached HEAD , описанное в пункте 2. (Вы можете также создать это же состояние с именем ветви, используя git checkout --detach
.)
Следствием пункта 4 выше является то, что git checkout origin/<em>name</em>
приводит к отсоединению HEAD, так же, как git checkout <em>hash-ID</em>
.
Это означает, что ваш скрипт может просто использовать git checkout <argument>
, так как он будетсделайте то же самое - создайте отдельный HEAD - если аргумент является идентификатором хэша или если это имя удаленного отслеживания, например origin/develop
.
Обратите внимание, однако, что если мы изменим этот оператор на чтение:
Простой git checkout <argument>
не подходит, поскольку он не будет сначала создавать, а затем извлекать локальную ветвь на основе существующего имени удаленного отслеживания, как git checkout <argument minus the leading origin/ part>
.
мы получаем истинное утверждение: git checkout develop
будет создать новая (локальная) ветка с именем develop
с именем origin/develop
(при условии, конечно, что локальная develop
еще не существует).Тем не менее, нет очевидной проблемы с простым разрешением <argument>
здесь и предоставлением пользователю develop
в качестве имени:
#! /bin/sh
git fetch && git checkout "$@"
, например.
Примечания
Здесь есть интересное следствие пунктов 1 и 2, а именно: каково значение HEAD
на данный момент действительно задает один из двух разных вопросов:
-
HEAD
подключен к ветке?Если да, то какая ветвь? - Каков хэш-идентификатор текущего коммита?
Команда git symbolic-ref HEAD
отвечает только на первый вопрос;git rev-parse HEAD
в основном отвечает на второй вопрос, но можно сказать, что он отвечает и на первый тоже / вместо этого.
В пункте 1 выше почти существует по определенной причине.Представьте, что вы только что создали новый, абсолютно пустой репозиторий. В этом репозитории нет коммитов , так какой коммит является текущим коммитом?
Эта ситуация проблематична для Git.Вы находитесь на ветке, а именно master
, которой не существует .Git называет это сиротская ветвь или ветвь, которую еще предстоит создать (в зависимости от того, какая часть Git выполняет вызов).Git обрабатывает это, чтобы сохранить имя ветки в .git/HEAD
без фактического создания самой ветки в справочной базе данных.Когда вы делаете новый коммит, это создает саму ветвь, и теперь проблема решена: вы находитесь на ветке, которая идентифицирует только что сделанный новый коммит, который является текущим коммитом, поэтому HEAD
называет как текущий коммит , так и текущую ветвь.
(Git может воссоздать эту слегка проблемную ситуацию по требованию, используя git checkout --orphan
, который записывает имя новой ветки в HEAD
без создания новой ветви.)