Распечатать символическое имя для HEAD

Я ищу команду Git, которая напечатает символическое имя для HEAD, Я использовал эту команду

$ git name-rev --name-only HEAD
master
$ git checkout HEAD~2
$ git name-rev --name-only HEAD
master~2

Однако я заметил, что это не работает на новом хранилище

$ git init
$ git name-rev --name-only HEAD
Could not get sha1 for HEAD. Skipping.

Я нашел этот обходной путь

$ git init
$ git symbolic-ref --short HEAD
master

Но это не работает на старых коммитах

$ git checkout HEAD~2
$ git symbolic-ref --short HEAD
fatal: ref HEAD is not a symbolic ref

Так что теперь у меня есть это, которое охватывает как новые репо, так и старые коммиты

$ git symbolic-ref -q --short HEAD || git name-rev --name-only HEAD
master

Мне просто интересно, это лучший способ сделать это? Такое ощущение, что это должно быть возможно с помощью одной команды.

2 ответа

Решение

Ты пишешь:

Я ищу команду Git, которая напечатает символическое имя для HEAD,

Следующего может быть достаточно, чтобы продемонстрировать, что то, что вы просите, не имеет смысла во всех ситуациях, просто потому, что HEAD не может быть однозначно связан с одной ссылкой. Читать дальше.

Какие git name-rev делает

в git-name-rev man-страницу, вы найдете следующее описание:

Получив коммит, выясните, где он находится по отношению к местным ссылкам. [...]

Более конкретно, git name-rev проверяет, <commit-ish> доступен из любой локальной ссылки (путем обработки их в лексикографическом порядке, например, develop до master).

Давайте посмотрим, что

$ git name-rev --name-only <commit-ish>

делает в разных случаях (--name-only флаг здесь случайный, так как его действие чисто косметическое).

Случай, в котором HEAD не отделен

Если HEAD не оторван, если я HEAD указывает на действительный ref (давайте назовем его myref), то тут двусмысленности нет

$ git name-rev --name-only HEAD

просто выводит

myref

поскольку myref ссылка однозначно связана с HEAD, Все идет нормально.

Случай, в котором HEAD отделен

В этом случае все не так просто. На самом деле, может быть одна или несколько ссылок, из которых <commit-ish> достижимо, или вообще не может быть.

Случай, в котором есть одна или несколько таких локальных ссылок

При первом обнаружении такой локальной ссылки, git name-rev печатает "относительную" символьную ссылку, то есть ревизию формы

<ref>~<n>

где <ref> обозначает местную ссылку, о которой идет речь, и <n> обозначает поколение. Например, если HEAD указывает непосредственно на коммит, который является прародителем master (master будучи единственной местной ссылкой), то

$ git name-rev HEAD

возвращается

master~2

Обратите внимание, однако, что в случае <commit-ish> достижимо из нескольких ссылок, одна из которых возвращена git name-rev является несколько произвольным, так как он продиктован только лексикографическим порядком (в котором команда проверяет локальные ссылки).

Случай, в котором нет такой локальной ссылки

Легко представить себе ситуации, в которых <commit-ish> достижимо ни от одной из местных ссылок. На самом деле, вот тот, который вы можете воспроизвести дома (стандартный вывод отсутствует):

# set things up
$ mkdir test
$ cd test
$ git init

# create a commit
$ touch README.md
$ git add README.md
$ git commit -m "add README"

# detach the HEAD (make it point directly to the tip of master, instead of to master itself)
$ git checkout $(git rev-parse master)

# create a second commit (while in detached-HEAD state)
$ printf "foo\n" > README.md
$ git commit -am "write 'foo' in README"

# attempt to find a symbolic name for HEAD 
$ git name-rev --name-only HEAD
undefined

Поскольку коммит DAG выглядит следующим образом,

A [master]
 \
  B [HEAD]

совершить B не доступен из единственной ссылки (master); следовательно, git name-rev сдается и просто возвращается undefined,

Заключение

Так как HEAD не гарантируется однозначная привязка к одной ссылке, то, что вы просите, не имеет смысла :p

Просто хочу добавить мое решение для вашего случая:

git symbolic-ref -q --short HEAD || git describe --all --always HEAD

Это касается веток, тегов, отдельных головок (коммитов) и новых репозиториев. Но теги будут возвращены как tags/0.1.0 например.

Другие вопросы по тегам