¿Cómo puedo saber si un commit es descendiente de otro commit?


Respuestas:


51

Si desea verificar esto mediante programación (por ejemplo, en el script), puede verificar si git merge-base A Bes igual a git rev-parse --verify A(entonces A es accesible desde B), o si lo es git rev-parse --verify B(entonces B es accesible desde A). git rev-parseaquí se necesita para convertir el nombre de confirmación en commit SHA-1 / commit id.

Usar git rev-listcomo en la respuesta VonC también es una posibilidad.

Editar: en Git moderno hay soporte explícito para esta consulta en forma de git merge-base --is-ancestor.


Si uno de los compromisos sobre los que está preguntando es una sugerencia de sucursal , entonces git branch --contains <commit>o git branch --merged <commit>podría ser una mejor solución no programática.


1
Posiblemente, la forma más rápida sería hacia git checkout -b quickcheck <more-recent-commit-ID>y luego git branch --contains <older-commit-ID>(y luego git branch -D quickcheckdeshacerse de la rama temporal).
— clee

2
Dos posibles enfoques, ambos mucho peores que el de la respuesta de @ MattR.
— jwg

66
@jwg: la respuesta de MattR es mejor, pero esta respuesta (y probablemente sea aceptada) es anterior a git 1.8.0 y git merge-base --is-ancestorpor 2 años.
— Jakub Narębski

@ JakubNarębski Muy bien, lo siento.
— jwg

2
En un gran repositorio (2 millones de commit), comparé la velocidad de git branch --contains <commit>y git merge-base --is-ancestor ...: 3m40s vs 0.14s
— hagello

259

Desde Git 1.8.0, esto se admite como una opción para merge-base:

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

Desde la página del manual:

--es-antepasado

Compruebe si el primero es ancestro del segundo y salga con el estado 0 si es verdadero o con el estado 1 si no. Los errores se señalan mediante un estado distinto de cero que no es 1.

Por ejemplo:

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

44
¡Agradable! Aquí hay una secuencia de comandos de shell que envuelve esta respuesta en algo con salida accesible para humanos: gist.github.com/simonwhitaker/6354592
— Simon Whitaker

1
En otras palabras: git merge-base THING --is-ancestor OF_THING && echo yes || echo nopor ejemplo:git merge-base my-feature-branch --is-ancestor master && echo yes || echo no
— user1735594

2
@smarber git merge-base --is-ancestor -- commit commitfunciona para los hashes a mi lado con git2.1.4 (Debian / Devuan 7.10 jessie) y 1.9.1 (Ubuntu 14.04 de confianza) que son bastante antiguos ahora. Funciona incluso para Debian wheezy, si lo hace sudo apt-get install git/wheezy-backports.
— Tino

15

Este tipo de operaciones se basa en la noción de rango de revisiones detalladas en la pregunta SO: " Diferencia en 'git log origin / master' vs 'git log origin / master ..' ".

git rev-list debería poder regresar de un commit, hasta otro si es accesible.

Entonces intentaría:

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

(Las confirmaciones de límite tienen el prefijo -)

Si la última confirmación mostrada es la misma que la primera confirmación en el git rev-listcomando, entonces es una confirmación accesible desde la segunda confirmación.

Si el primer commit no es accesible desde el segundo, no git rev-listdebería devolver nada.

git rev-list --boundary A..B

terminaría por A, si Aes accesible desde B.
Es lo mismo que:

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

, con Buna referencia positiva y Auna referencia negativa .
Comenzará en By retrocederá a través del gráfico hasta que encuentre una revisión a la que se pueda acceder A.
Yo diría que si Aes directamente accesible B, se encontrará (y se mostrará, debido a la --boundaryopción) en Así mismo.


Esto suena como un caso de uso bastante común que me sorprende que git aún no haya publicado un comando de "porcelana" que hace exactamente esto.
— Lawrence I. Siden

1
@lsiden: cierto. Nota al margen: no olvide que para verificar algo mediante programación , no debe usar el comando de porcelana (como en stackoverflow.com/questions/6976473/… ), sino comandos de plomería (como se ilustra en stackoverflow.com/questions / 3878624 / ... )
— VonC

¡Oh, hombre, parece que tengo que regresar y trabajar en mis habilidades de scripting de Shell!
— Lawrence I. Siden

1
pregunta: ¿por qué -85e54e2...el fragmento de código tiene un signo menos? también un error tipográfico: "... es lo mismo que la primera confirmación ..."
— sdaau

1
@sdaau -significa que es un compromiso de límite. He editado la respuesta para aclarar eso, así como para actualizar los enlaces de documentos y corregir el error tipográfico para esta respuesta de 5 años.
— VonC

11

Otra forma sería usar git logy grep.

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

Esto producirá una línea de salida si commit def456 es un antecesor de commit abc123, o no hay salida de otra manera.

Por lo general, puede salirse con la suya omitiendo el --prettyargumento, pero es necesario si desea asegurarse de que solo busca a través de hashes de confirmación reales y no a través de comentarios de registro, etc.


Esperaba que esta solución fuera lenta, pero en realidad es bastante rápida, incluso para un proyecto con más de 20k commits
— Renato Zannon

2
en lugar de --prettyusar --oneline: git log --oneline ce2ee3d | grep ec219ccfunciona muy bien
— gens


1

git show-branch branch-sha1 commit-sha1

Dónde:

  • branch-sha1: el sha1 en su rama que desea verificar
  • commit-sha1: el sha1 del commit con el que quieres verificar

0

Si está usando git merge-base --is-ancestor, asegúrese de usar Git 2.28 (Q3 2020)

Con Git 2.28 (Q3 2020), algunos campos en " struct commit" que no tienen que estar siempre presentes se han movido para confirmar losas.

Ver commit c752ad0 , commit c49c82a , commit 4844812 , commit 6da43d9 (17 de junio de 2020) por Abhishek Kumar ( abhishekkumar2718) .
(Fusión por Junio ​​C Hamano - gitster- en commit d80bea4 , 06 de julio de 2020)

commit-graph: presentar commit_graph_data_slab

Firmado por: Abhishek Kumar

La estructura commit se usa en muchos contextos. Sin embargo, los miembros generationy graph_possolo se usan para operaciones relacionadas con gráficas de confirmación y, de lo contrario, desperdician memoria.

Este desperdicio habría sido más pronunciado a medida que hacemos la transición al número de generación v2, que utiliza el número de generación de 64 bits en lugar de los 32 bits actuales.

Como a menudo se accede a ellos juntos, vamos a introducir struct commit_graph_datay moverlos a una commit_graph_datalosa.

Si bien el conjunto de pruebas en general se ejecuta tan rápido como master(serie: 26m48s,: master27m34s, más rápido en 2.87%), ciertos comandos como git merge-base --is-ancestorse ralentizaron en un 40% como descubrió Szeder Gábor .
Después de minimizar el acceso a la losa de compromiso, la desaceleración persiste pero se acerca al 20%.

Derrick Stolee cree que la desaceleración es atribuible al algoritmo subyacente más que a la lentitud del acceso de commit-slab y haremos un seguimiento en una serie posterior.


-1

Construyendo sobre la respuesta de itub, en caso de que necesite hacer esto para todas las etiquetas en el repositorio:

for i in `git tag` ; do echo -ne $i "\t" ; git log --pretty=format:%H $i | (grep <commit to find> || echo ""); done
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.