web-dev-qa-db-fra.com

Comment savoir si un commit est l'ancêtre d'un autre commit (ou vice-versa)?

Git est un DAG d'instantanés, chaque nœud du graphique représentant un commit. Chaque validation peut avoir des validations parentales 'n'.

Étant donné deux commits, existe-t-il un moyen unique et concis de discerner "l'ordre" de ces deux dans le DAG. git rev-list semble être le plus prometteur, mais je n'arrive pas à trouver la bonne incantation.

Idéalement, j'aurais quelque chose comme ceci

$ git related hash1 hash2
hash1 is ancestor of hash2

OR

hash2 is ancestor of hash1

OR

hash1 unrelated to hash2

OR

hash1 is equal to hash2
62
Chris Cleeland

Utilisation git merge-base --is-ancestor <commit1> <commit2>

Il existe plusieurs façons de trouver la réponse à cette question. Le plus simple est d'utiliser

git merge-base --is-ancestor <commit> <commit>

De la documentation de git merge-base :

--is-ancestor

Vérifiez si le premier <commit> est un ancêtre du second <commit>, et quittez avec l'état 0 si vrai, ou avec l'état 1 sinon. Les erreurs sont signalées par un état différent de zéro différent de 1.

Autres options

journal git avec triple point ... notation

Une autre option consiste à utiliser git log et utilisez la notation à trois points ... pour dire à Git de sortir l'union définie des validations enfants, moins l'intersection définie. Fondamentalement, il vous indique comment un ensemble de validations a divergé les uns des autres:

$ git log --oneline --graph --left-right \
--first-parent --decorate <commit1>...<commit2>

La commande ci-dessus vous montrera les validations accessibles depuis commit1 ou commit2, mais pas les deux, c'est-à-dire C1 UNION C2 - C1 INTERSECTION C2, en termes d'opérations définies.

Si aucun commit n'est parent de l'autre, vous verrez les commits enfants des deux, mais si l'un est un ancêtre de l'autre, vous ne verrez que la sortie du commit descendant, car l'ancêtre est contenu dans le chemin du descendant, et est donc exclu de la sortie.

Vous pouvez en savoir plus sur git log et notation à trois points à partir des ressources suivantes:

  1. git-log (1) .
  2. gitrevisions (1): Spécification des plages .
  3. Sélection de révision .

git branch - contient une option

git-rev-list (1) semble pouvoir être utilisé pour y répondre. Une autre façon consiste à simplement attacher des étiquettes de branche temporaires aux validations que vous souhaitez tester, puis à utiliser le --contains option pour git branch :

git branch --contains <commit-to-test>

La sortie sera toutes les branches qui contiennent le commit quelque part dans leur arbre de commit, donc en utilisant une branche temporaire sur l'autre commit, vous pouvez voir si le commit que vous testez est un ancêtre.

De la documentation:

--contains [<commit>]

Liste uniquement les branches qui contiennent le commit spécifié (HEAD si non spécifié).

65
user456814

Le script Shell suivant pourrait faire l'affaire:

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

Ou, pour bien l'envelopper dans un alias 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'
9
helmbert
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
2
michas
git log  --oneline -1  OLD_SHA..NEW_SHA

Si cela vous donne un journal, OLD_SHA est le parent de NEW_SHA.

1
jin

Pour s'appuyer sur l'excellent _ helmbert git related alias, voici une version qui accepte également les noms de branche (ou HEAD etc) comme arguments, plutôt que de simplement valider les identifiants:

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'
0
Peter Reay