Что является ближайшим тегом в прошлом относительно ветвления в Git?

История диаграмм меток не является линейной. Люди не просто отмечают базовый уровень (master).

Например, наиболее ценные библиотеки JS/CSS выполняют выпуск по ветке с базовой линии, чтобы сохранить чистую историю различий. Они фиксируют артефакты выпуска (скомпилированные/уменьшенные JS/CSS), поэтому пользователи могут легко захватывать артефакты без необходимости создавать. Если они помечаются на master, то master история будет иметь огромные все-все-разные отличия в артефактах сборки.

Реальный пример:

bash# cd js/jquery
/home/user/devel/js/jquery

bash# git remote -v
origin  https://github.com/jquery/jquery.git (fetch)

bash# git co master
Already on 'master'

bash# git describe --tags
2.1.0-beta1-590-g47ccf3d

bash# git log --graph  --decorate --simplify-by-decoration --oneline --all
* 70605c8 (origin/master, origin/HEAD) Ajax: Only form-encode requests with a body
* 47ccf3d (HEAD -> master) Attributes: do not set properties to false when removing booleans
| * 8339185 (origin/compat) Tests: Make regexes for iOS devices more rigid
| | * f9846ae (tag: 3.0.0-alpha1) 3.0.0-alpha1
| |/  
|/|   
...
* | 1185427 (tag: 2.1.0-beta1) Tagging the 2.1.0-beta1 release.

Трюки из Как получить последнее имя тега в текущей ветке в Git? бесполезны в реальном мире, для:

git describe --tags

В приведенном выше примере я получаю 2.1.0-beta1, но последнее усилие - 3.0.0-alpha1.

Лучший способ, которым я сейчас пользуюсь, - это просмотреть свернутую историю фиксации вручную:

git log --graph --decorate --simplify-by-decoration --oneline --all

Ответ 1

После перехода на Git docs мне удалось написать:

$ git tag \
     | while read t; do \
         b=`git merge-base HEAD $t`; \
         echo `git log -n 1 $b --format=%ai` $t; \
       done | sort
...
2014-04-18 17:17:51 -0400 2.1.1-rc2
2014-04-30 10:43:39 -0400 2.1.1
2014-05-18 20:47:37 +0400 2.1.2
2014-05-18 20:47:37 +0400 2.1.3
2014-05-18 20:47:37 +0400 2.1.4
2015-07-13 15:01:33 -0400 3.0.0-alpha1

Как я уверен, Hg сделал соответствующее решение:

$ hg convert \
    $(git -C jquery/ rev-parse --branches --remotes --tags \
      | sed 's=.*=--rev &=') \
  jquery/ jquery-hg/

$ cd jquery-hg
$ hg up -r master

$ hg log -r 'tag()' --template '{node} {tags}\n' \
    | while read r t; do \
        hg log -r "ancestor($r,.)" --template "{date|isodate} {node} $t \n"; \
      done | sort

2014-06-16 03:08 +0400 f6f4d6eb708a33f714a2e0003cb7087762407348 2.1.2 
2014-06-16 03:08 +0400 f6f4d6eb708a33f714a2e0003cb7087762407348 2.1.3 
2014-06-16 03:08 +0400 f6f4d6eb708a33f714a2e0003cb7087762407348 2.1.4 
2015-07-13 15:01 -0400 4abe7e961f0e5eb0e75f03030a80a128553f34c1 3.0.0-alpha1 

Я могу добавить псевдоним к ~/.bashrc, и этот код занимает около 4 секунд в источниках jQuery/Hibernate/Lunix/Spring, но некоторые странные заполнения не оставляют меня. Есть ли однолинейное решение?

ОБНОВЛЕНИЕ Я написал длинный ответ в fooobar.com/info/4969/... Вот важные части:

Поскольку Git использует DAG, а не линейную историю - трудно определить метрику расстояния, поэтому мы можем сказать - о, что rev наиболее близок к моему HEAD!

Некоторое разумное определение расстояния между тегом и ревизией:

  • длина кратчайшего пути из HEAD, чтобы объединить базу с тегом (не знаю, кому вычислить команду git)
  • date базы слияния между HEAD и тегом (см. выше script)
  • количество оборотов, доступное из HEAD, но недоступное из тега (см. ниже script)

Script, которые сортируют теги в соответствии с числом оборотов, доступным из HEAD, но недоступным из тега:

$ git tag \
    | while read t; do echo `git rev-list --count $t..HEAD` $t; done \
    | sort -n

Если в истории вашего проекта есть странные даты на фиксации (из-за пересогласования или другой перезаписи истории или какого-нибудь придурка забыть заменить батарею BIOS или другие магии, которые вы делаете в истории) используйте script.