Comment puis-je savoir si un commit est le descendant d'un autre commit?


Réponses:


51

Si vous voulez vérifier cela par programme (par exemple dans un script), vous pouvez vérifier si git merge-base A Best égal à git rev-parse --verify A(alors A est accessible depuis B), ou si c'est le cas git rev-parse --verify B(alors B est accessible depuis A). git rev-parseest ici nécessaire pour convertir le nom du commit en commit SHA-1 / commit id.

Utiliser git rev-listcomme dans la réponse VonC est également possible.

Edit: dans Git moderne, il existe un support explicite pour cette requête sous la forme de git merge-base --is-ancestor.


Si l'un des commits que vous demandez est une astuce de branche , alors git branch --contains <commit>ou git branch --merged <commit>pourrait être une meilleure solution non programmatique.


1
Le moyen le plus rapide serait peut-être de git checkout -b quickcheck <more-recent-commit-ID>puis git branch --contains <older-commit-ID>(et ensuite git branch -D quickcheckde se débarrasser de la branche temporaire).
clee

2
Deux approches possibles, toutes deux bien pires que celle de la réponse de @ MattR.
jwg

6
@jwg: La réponse MattR est meilleure, mais cette réponse (et probablement acceptée) est antérieure à git 1.8.0 et git merge-base --is-ancestorde 2 ans.
Jakub Narębski

@ JakubNarębski Très bien, désolé.
jwg

2
Dans un grand référentiel (2 millions de commits), j'ai comparé la vitesse de git branch --contains <commit>et git merge-base --is-ancestor ...: 3m40s vs 0,14s
hagello

259

À partir de Git 1.8.0, ceci est pris en charge en tant qu'option pour merge-base:

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

Depuis la page de manuel:

--est-ancêtre

Vérifiez si le premier est un ancêtre du second et quittez avec le statut 0 si vrai, ou avec le statut 1 dans le cas contraire. Les erreurs sont signalées par un état différent de zéro qui n'est pas 1.

Par exemple:

git merge-base --is-ancestor origin/master master; echo $?

4
Agréable! Voici un script shell qui résume cette réponse dans quelque chose avec une sortie humainement réalisable
Simon Whitaker

1
En d'autres termes: git merge-base THING --is-ancestor OF_THING && echo yes || echo nopar exemple:git merge-base my-feature-branch --is-ancestor master && echo yes || echo no
user1735594

2
@smarber git merge-base --is-ancestor -- commit commitfonctionne pour les hachages à mes côtés avec git2.1.4 (Debian / Devuan 7.10 jessie) et 1.9.1 (Ubuntu 14.04 trusty) qui sont plutôt anciens maintenant. Cela fonctionne même pour Debian wheezy, si vous le faites sudo apt-get install git/wheezy-backports.
Tino

15

Ce type d'opérations repose sur la notion de plage de révisions détaillée dans la question SO: " Différence entre 'git log origin / master' vs 'git log origin / master ..' ".

git rev-list devrait être en mesure de revenir d'un commit, jusqu'à un autre s'il est accessible.

Alors j'essaierais:

git rev-list --boundary 85e54e2408..0815fcf18a
0815fcf18a19441c1c26fc3495c4047cf59a06b9
8a1658147a460a0230fb1990f0bc61130ab624b2
-85e54e240836e6efb46978e4a1780f0b45516b20

(Les commits de limite sont préfixés par -)

Si le dernier commit affiché est le même que le premier commit dans la git rev-listcommande, alors il s'agit d'un commit accessible à partir du deuxième commit.

Si le premier commit n'est pas accessible à partir du second, git rev-listne doit rien renvoyer.

git rev-list --boundary A..B

finirait par A, si Aest accessible à partir de B.
C'est la même chose que:

git rev-list --boundary B --not A

, avec Bune référence positive et Aune référence négative .
Il commencera à Bet reviendra dans le graphique jusqu'à ce qu'il rencontre une révision accessible à partir de A.
Je dirais que s'il Aest directement accessible depuis B, il se rencontrera (et s'affichera, à cause de l' --boundaryoption) A.


Cela ressemble à un cas d'utilisation assez courant que je suis surpris que git n'ait pas encore publié une commande "porcelain" qui fait exactement cela.
Lawrence I. Siden

1
@lsiden: vrai. Remarque: n'oubliez pas que pour vérifier quelque chose par programme , vous n'êtes pas censé utiliser la commande porcelain, (comme dans stackoverflow.com/questions/6976473/… ), mais les commandes de plomberie (comme illustré dans stackoverflow.com/questions / 3878624 /… )
VonC

Oh, mec, on dirait que je dois revenir en arrière et travailler sur mes côtelettes de script Shell!
Lawrence I. Siden

1
question: pourquoi le -85e54e2...dans l'extrait de code a-t-il un signe moins? également une faute de frappe possible: "... est le même que le premier commit ..."
sdaau

1
@sdaau -signifie qu'il s'agit d'un commit de limite. J'ai modifié la réponse pour rendre cela plus clair, ainsi que pour actualiser les liens vers la documentation et corriger la faute de frappe pour cette réponse vieille de 5 ans.
VonC

11

Une autre façon serait d'utiliser git loget grep.

git log --pretty=format:%H abc123 | grep def456

Cela produira une ligne de sortie si commit def456 est un ancêtre de commit abc123, ou aucune sortie autrement.

Vous pouvez généralement vous en sortir en omettant l' --prettyargument, mais cela est nécessaire si vous voulez vous assurer de ne rechercher que dans les hachages de validation réels et non dans les commentaires de journal, etc.


Je m'attendais à ce que cette solution soit lente, mais elle est en fait assez rapide, même pour un projet avec 20k + commits
Renato Zannon

2
au lieu d' --prettyutiliser --oneline: git log --oneline ce2ee3d | grep ec219ccfonctionne très bien
gens


1

git show-branch branche-sha1 commit-sha1

Où:

  • branch-sha1: le sha1 de votre branche que vous voulez vérifier
  • commit-sha1: le sha1 du commit que vous voulez vérifier

0

Si vous utilisez git merge-base --is-ancestor, assurez-vous d'utiliser Git 2.28 (Q3 2020)

Avec Git 2.28 (Q3 2020), quelques champs de " struct commit" qui ne doivent pas toujours être présents ont été déplacés vers les slabs de validation.

Voir commit c752ad0 , commit c49c82a , commit 4844812 , commit 6da43d9 (17 juin 2020) par Abhishek Kumar ( abhishekkumar2718) .
(Fusionné par Junio ​​C Hamano - gitster- in commit d80bea4 , 06 juil.2020 )

commit-graph: présenter commit_graph_data_slab

Signé par: Abhishek Kumar

Le struct commit est utilisé dans de nombreux contextes. Cependant, les membres generationet graph_posne sont utilisés que pour les opérations liées au graphe de validation et gaspillent de la mémoire.

Ce gaspillage aurait été plus prononcé lorsque nous passons au numéro de génération v2, qui utilise le numéro de génération 64 bits au lieu des 32 bits actuels.

Comme ils sont souvent consultés ensemble, introduisons struct commit_graph_dataet déplaçons-les vers une commit_graph_datadalle.

Alors que l'ensemble de la suite de tests fonctionne aussi vite que master, (série: 26m48s,: master27m34s, plus rapide de 2,87%), certaines commandes comme git merge-base --is-ancestoront été ralenties de 40% comme l'a découvert Szeder Gábor .
Après avoir minimisé l'accès à la dalle de validation, le ralentissement persiste mais est plus proche de 20%.

Derrick Stolee pense que le ralentissement est attribuable à l'algorithme sous-jacent plutôt qu'à la lenteur de l'accès aux commit-slab et nous ferons un suivi dans une série ultérieure.


-1

En vous basant sur la réponse d'itub, au cas où vous auriez besoin de le faire pour toutes les balises du référentiel:

for i in `git tag` ; do echo -ne $i "\t" ; git log --pretty=format:%H $i | (grep <commit to find> || echo ""); done
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.