Как я могу определить, является ли один коммит предком другого (или наоборот)?
Git - это DAG моментальных снимков, где каждый узел на графике представляет коммит. Каждый коммит может иметь n родительских коммитов.
Учитывая любые два коммита, существует ли единственный, краткий способ различить "порядок" этих двух в DAG. git rev-list
кажется наиболее перспективным, но я не могу найти правильное заклинание.
В идеале у меня было бы что-то вроде следующего
$ git related hash1 hash2
hash1 is ancestor of hash2
ИЛИ ЖЕ
hash2 is ancestor of hash1
ИЛИ ЖЕ
hash1 unrelated to hash2
ИЛИ ЖЕ
hash1 is equal to hash2
5 ответов
использование git merge-base --is-ancestor <commit1> <commit2>
Существует несколько способов найти ответ на этот вопрос. Самое простое - это использовать
git merge-base --is-ancestor <commit> <commit>
Из документации для git merge-base
:
--is-ancestor
Проверьте, если первый
<commit>
является предком второго<commit>
и выйдите со статусом 0, если истина, или со статусом 1, если нет. Ошибки сигнализируются ненулевым статусом, отличным от 1.
Другие опции
мерзавец с тройной точкой ...
обозначение
Другой вариант заключается в использовании git log
и использовать обозначение тройной точки ...
чтобы сказать Git вывести объединение множеств дочерних коммитов, минус пересечение множеств. В основном, это говорит о том, как набор коммитов отличается друг от друга:
$ git log --oneline --graph --left-right \
--first-parent --decorate <commit1>...<commit2>
Приведенная выше команда покажет вам коммиты, которые доступны из commit1
или же commit2
, но не оба, то есть С1 СОЮЗ С2 - С1 Пересечение С2, с точки зрения операций над множествами.
Если ни один из коммитов не является родителем другого, вы увидите, что оба коммита являются дочерними, но если один является предком другого, вы увидите только выходные данные для коммитов-потомков, поскольку предок содержится в пути. потомка, и, следовательно, исключен из вывода.
Вы можете прочитать больше о git log
и обозначение тройной точки из следующих ресурсов:
git branch - содержит опцию
git-rev-list(1), кажется, может быть использован для ответа на этот вопрос. Другой способ - просто прикрепить временные метки веток к коммитам, которые вы хотите протестировать, а затем использовать --contains
вариант для git branch
:
git branch --contains <commit-to-test>
Выходными данными будут все ветви, которые содержат коммит где-то в их дереве коммитов, поэтому, используя временную ветвь для другого коммита, вы можете увидеть, является ли тестируемый вами коммит предком.
Из документации:
--contains [<commit>]
Только те ветви списка, которые содержат указанный коммит (HEAD, если не указан).
Следующий сценарий оболочки может помочь:
if git rev-list $SHA1 | grep -q $SHA2 ; then echo "$SHA2 is ancestor of $SHA1"
elif git rev-list $SHA2 | grep -q $SHA1 ; then echo "$SHA1 is ancestor of $SHA2"
else echo "$SHA1 unrelated to $SHA2" ; fi
Или, чтобы аккуратно обернуть это в псевдоним git:
git config --global alias.related '!function git_related() { if git rev-list $1 | grep -q $2 ; then echo "$2 is ancestor of $1" ; elif git rev-list $2 | grep -q $1 ; then echo "$1 is ancestor of $2" ; else echo "$1 unrelated to $2" ; fi } ; git_related $1 $2'
if (( $(git rev-list $1..$2|wc -l) == 0 )); then echo "$2 is ancestor of $1"
elif (( $(git rev-list $2..$1|wc -l) == 0 )); then echo "$1 is ancestor of $2"
else echo "$1 and $2 are unrelated"
fi
git log --oneline -1 OLD_SHA..NEW_SHA
Если это дает вам некоторый журнал, то OLD_SHA является родителем NEW_SHA.
Чтобы построить на @ Helmbert's отлично git related
псевдоним, вот версия, которая также принимает имена ветвей (или HEAD и т. д.) в качестве аргументов, а не просто идентификаторы коммитов:
git config --global alias.related '!function git_related() { commit1=`git log -n 1 --format="%h" $1` ; commit2=`git log -n 1 --format="%h" $2` ; if git rev-list $commit1 | grep -q $commit2 ; then echo "$2 is ancestor of $1" ; elif git rev-list $commit2 | grep -q $commit1 ; then echo "$1 is ancestor of $2" ; else echo "$1 unrelated to $2" ; fi } ; git_related $1 $2'