Dada una rama, me gustaría ver una lista de confirmaciones que existen solo en esa rama. En esta pregunta , discutimos formas de ver qué confirmaciones están en una rama pero no en una o más ramas especificadas.
Esto es ligeramente diferente. Me gustaría ver lo que cometa, está en una, pero no en las otras ramas.
El caso de uso se encuentra en una estrategia de ramificación en la que algunas ramas solo deben fusionarse y nunca comprometerse directamente. Esto se usaría para verificar si se han realizado confirmaciones directamente en una rama de "solo combinación".
EDITAR: A continuación se muestran los pasos para configurar un repositorio git ficticio para probar:
git init
echo foo1 >> foo.txt
git add foo.txt
git commit -am "initial valid commit"
git checkout -b merge-only
echo bar >> bar.txt
git add bar.txt
git commit -am "bad commit directly on merge-only"
git checkout master
echo foo2 >> foo.txt
git commit -am "2nd valid commit on master"
git checkout merge-only
git merge master
Solo debería aparecer la confirmación con el mensaje "confirmación incorrecta directamente en solo combinación", que se realizó directamente en la rama de solo combinación.
git log ^branch1 ^branch2 merge-only-branch
sintaxis?git log ^branch1 ^branch2 merge-only-branch
requiere enumerar cada rama. Eso se puede evitar con un uso inteligente de bash / grep (vea mi respuesta a continuación), pero espero que git tenga algún soporte incorporado para esto. Tiene razón en que supone que todas las ramas de fusión son remotas (solo las locales son tan buenas como inexistentes para otros desarrolladores). El uso--no-merges
omite todas las confirmaciones que se fusionaron y luego se eliminó la rama de fusión de origen original, por lo que se supone que las ramas de fusión de se mantienen hasta que se fusionan con una rama que no es de fusión solo (es decir, maestra).Respuestas:
Acabamos de encontrar esta elegante solución
En su ejemplo, por supuesto, la confirmación inicial todavía aparece.
esta respuesta no responde exactamente a la pregunta, porque la confirmación inicial todavía aparece. Por otro lado, muchas personas que vienen aquí parecen encontrar la respuesta que buscan.
fuente
initial valid commit
, que es parte de ambasmerge-only
master
ramas y . Sin embargo, si uno pasa por el esfuerzo de poner el nombre de la rama actual al final seguido de nombres de rama con prefijo ^ de los que se sabe que se originó la rama actual, resuelve la mitad de los problemas (excluyendo las cosas que se fusionaron). Ej .:git log --first-parent --no-merges merge-only ^master
git log --first-parent --no-merges | grep <branch_name>
Cortesía de mi querido amigo Redmumba :
... dónde
origin/merge-only
está el nombre de la rama de solo combinación remota. Si trabaja en un repositorio de git solo local, sustitúyalorefs/remotes/origin
porrefs/heads
y sustituya el nombre de la rama remotaorigin/merge-only
con el nombre de la rama localmerge-only
, es decir:fuente
git for-each-ref
para enumerar todos los nombres de referencia en el origen ygrep -v
para omitir la rama de solo combinación.git log
toma una--not
opción, a la que pasamos nuestra lista de todas las referencias (excepto la rama de solo fusión). Si tiene una respuesta más elegante al problema, escuchémosla./*
de losgit for-each-refs
comandos se basa en no coincidir con algún archivo existente y no tenerfailglob
onullglob
establecer (las opciones de bash , otras shells varían). Debe citar / escapar de los asteriscos o simplemente dejar el final/*
(losgit for-each-ref
patrones pueden coincidir "desde el principio hasta una barra oblicua"). Tal vez usegrep -Fv refs/remotes/origin/foo
(refs/heads/foo
) para ser más estricto sobre qué referencias se eliminan.git log --no-merges B1 --not B2
donde B1 es la rama que le interesa y B2 es la rama con la que desea comparar B1. Tanto B1 como B2 pueden ser sucursales locales o remotas, por lo que puede especificargit log --no-merges master --not origin/master
, o incluso especificar dos sucursales remotas.Esto le mostrará todas las confirmaciones realizadas en su rama.
fuente
origin/branchName
apuntará al jefe de la rama remota YHEAD
apuntará al commitid de la última confirmación local en esa rama. Así que esto no funcionará cuando haya usado git push.La respuesta de @Prakash funciona. Solo por claridad ...
enumera las confirmaciones en la rama de características pero no en la rama ascendente (normalmente su maestro).
fuente
Quizás esto podría ayudar:
fuente
Prueba esto:
Básicamente,
git rev-list --all ^branch
obtiene todas las revisiones que no están en la rama y luego todas las revisiones en el repositorio y restan la lista anterior, que son solo las revisiones en la rama.Después de los comentarios de @ Brian:
De la documentación de git rev-list:
List commits that are reachable by following the parent links from the given commit(s)
Entonces un comando como
git rev-list A
donde A es una confirmación enumerará las confirmaciones que son accesibles desde A, incluida A.Con eso en mente, algo como
git rev-list --all ^A
enumerará las confirmaciones no accesibles desde A
Entonces
git rev-list --all ^branch
enumerará todas las confirmaciones no accesibles desde la punta de la rama. Lo que eliminará todas las confirmaciones en la rama, o en otras palabras, las confirmaciones que están solo en otras ramas.Ahora vamos a
git rev-list --all --not $(git rev-list --all ^branch)
Esto sera como
git rev-list --all --not {commits only in other branches}
Así que queremos enumerar los
all
que no son accesibles desdeall commits only in other branches
Que es el conjunto de confirmaciones que solo están en la rama. Tomemos un ejemplo simple:
Aquí el objetivo es obtener D y E, las confirmaciones no en ninguna otra rama.
git rev-list --all ^branch
dar solo BAhora,
git rev-list --all --not B
es a lo que llegamos. Lo que también esgit rev-list -all ^B
: queremos que no se pueda acceder a todas las confirmaciones desde B. En nuestro caso, son D y E. Que es lo que queremos.Espero que esto explique cómo funciona correctamente el comando.
Editar después del comentario:
Después de los pasos anteriores, si lo hace
git rev-list --all --not $(git rev-list --all ^merge-only)
, obtendrá el compromiso que estaba buscando: el"bad commit directly on merge-only"
.Pero una vez que realice el último paso en sus pasos,
git merge master
el comando no dará el resultado esperado. Porque a partir de ahora no hay confirmación que no esté en merge-only ya que la confirmación adicional en master también se ha fusionado para merge-only. Entoncesgit rev-list --all ^branch
da un resultado vacío y, porgit rev-list -all --not $(git rev-list --all ^branch)
lo tanto , dará todas las confirmaciones solo en combinación.fuente
xargs -L 1 -t git branch -a --contains
muestra muchos falsos positivos (confirmaciones que, de hecho, están en otras ramas). Intenté con y sin--no-merges
. ¡Gracias por responder!git rev-list --all ^branch
le dará todas las confirmaciones que no están incluidasbranch
. Usted está restando después de que en la lista que están enbranch
; pero, por definición, todas las confirmaciones que no están incluidas nobranch
están incluidasbranch
, por lo que no resta nada. Lo que jimmyorr busca son confirmaciones que estén enbranch
pero nomaster
, ni en ninguna otra rama. No desea restar las confirmaciones que no están incluidasbranch
; desea restar las confirmaciones que están en cualquier otra rama.branch
, pero también lo hacegit rev-list branch
. Estás escribiendogit rev-list branch
de una manera más complicada (y más lenta). No funciona responder a la pregunta, que es cómo encontrar todas las confirmacionesbranch
que no están en ninguna otra rama .Otra variación de las respuestas aceptadas, para usar con
master
git log origin/master --not $(git branch -a | grep -Fv master)
Filtra todas las confirmaciones que ocurren en cualquier rama que no sea la maestra.
fuente
Esta no es exactamente una respuesta real, pero necesito acceso al formato y mucho espacio. Intentaré describir la teoría detrás de lo que considero las dos mejores respuestas: la aceptada y la (al menos actualmente) mejor clasificada . Pero, de hecho, responden a diferentes preguntas .
Las confirmaciones en Git suelen estar "en" más de una rama a la vez. De hecho, de eso se trata la pregunta. Dado:
donde las letras mayúsculas representan los ID de hash de Git reales, a menudo buscamos solo confirmaciones
H
o solo confirmacionesI-J
en nuestragit log
salida. Las confirmaciones hastaG
están en ambas ramas, por lo que nos gustaría excluirlas.(Tenga en cuenta que en los gráficos dibujados como este, las confirmaciones más nuevas están hacia la derecha. Los nombres seleccionan la confirmación única más a la derecha en esa línea. Cada una de esas confirmaciones tiene una confirmación principal, que es la confirmación a su izquierda: el padre de
H
esG
, y el padre deJ
esI
. El padre deI
es deG
nuevo. El padre deG
esF
, yF
tiene un padre que simplemente no se muestra aquí: es parte de la...
sección).Para este caso particularmente simple, podemos usar:
para ver
I-J
, o:para ver
H
solo. El nombre del lado derecho, después de los dos puntos, le dice a Git: sí, estas confirmaciones . El nombre del lado izquierdo, antes de los dos puntos, le dice a Git: no, no estas confirmaciones . Git comienza por el final , en la confirmaciónH
o confirmación,J
y funciona al revés . Para (mucho) más sobre esto, consulte Think Like (a) Git .De la forma en que está redactada la pregunta original, el deseo es encontrar confirmaciones que sean accesibles desde un nombre en particular, pero no desde cualquier otro nombre en la misma categoría general. Es decir, si tenemos una gráfica más compleja:
podríamos elegir uno de estos nombres, como
name4
oname3
, y preguntar: ¿ qué confirmaciones se pueden encontrar con ese nombre, pero no con los otros nombres? Si elegimosname3
la respuesta es comprometerseL
. Si elegimosname4
, la respuesta es ningún compromiso: el compromiso de que losname4
nombres es compromisoN
pero compromisoN
se puede encontrar comenzando enname5
y trabajando hacia atrás.La respuesta aceptada funciona con nombres de seguimiento remoto, en lugar de nombres de sucursales, y le permite designar uno, el que está escrito,
origin/merge-only
como el nombre seleccionado y mirar todos los demás nombres en ese espacio de nombres. También evita mostrar fusiones: si seleccionamosname1
como el "nombre interesante" y decimos mostrarme confirmaciones que son accesibles desdename1
pero no cualquier otro nombre , veremos la confirmación de fusiónM
así como la confirmación regularI
.La respuesta más popular es bastante diferente. Se trata de atravesar el gráfico de confirmaciones sin seguir ambos tramos de una fusión y sin mostrar ninguna de las confirmaciones que son fusiones. Si comenzamos con
name1
, por ejemplo, no mostraremosM
(es una fusión), pero asumiendo que el primer padre de la fusiónM
es un compromisoI
, ni siquiera veremos los compromisosJ
yK
. Vamos a terminar mostrando cometerI
, y también se comprometeH
,G
,F
, y así sucesivamente, ninguno de estos son confirmaciones de mezcla y todos son accesibles por a partir deM
y trabajando hacia atrás, visitando sólo el primero de los padres de cada combinación de comprometerse.La respuesta más popular es bastante adecuada, por ejemplo, para ver
master
cuándomaster
se pretende que sea una rama de solo combinación. Si todo el "trabajo real" se realizó en las ramas laterales que posteriormente se fusionaronmaster
, tendremos un patrón como este:donde todos los nombres sin letra
o
confirmaciones sin son confirmaciones ordinarias (sin fusión)M
yN
son confirmaciones de fusión. ComprometerseI
es la inicial cometer: el primer cometer jamás se ha hecho, y el único que debería estar en la maestra que no es una fusión cometió. Si elgit log --first-parent --no-merges master
programa muestra algún compromiso diferente aI
, tenemos una situación como esta:donde queremos ver la confirmación
*
que se realizó directamentemaster
, no fusionando alguna rama de características.En resumen, la respuesta popular es excelente para mirar
master
cuándomaster
se debe combinar solo, pero no es tan buena para otras situaciones. La respuesta aceptada funciona para estas otras situaciones.¿Son nombres de seguimiento remoto como
origin/master
nombres de sucursales ?Algunas partes de Git dicen que no lo son:
dice
on branch master
, pero:dice
HEAD detached at origin/master
. Prefiero estar de acuerdo congit checkout
/git switch
:origin/master
no es un nombre de rama porque no se puede "acceder" a él.La respuesta aceptada usa nombres de seguimiento remoto
origin/*
como "nombres de sucursales":La línea media, que invoca
git for-each-ref
, itera sobre los nombres de seguimiento remoto para el control remoto nombradoorigin
.La razón por la que esta es una buena solución al problema original es que aquí estamos interesados en los nombres de las ramas de otra persona , en lugar de los nombres de nuestras ramas. Pero eso significa que hemos definido rama como algo diferente a nuestros nombres de rama . Eso está bien: solo tenga en cuenta que está haciendo esto, cuando lo haga.
git log
atraviesa alguna (s) parte (s) del gráfico de confirmaciónLo que realmente estamos buscando aquí es una serie de lo que he llamado daglets: mira ¿Qué queremos decir exactamente con "rama"? Es decir, estamos buscando fragmentos dentro de algún subconjunto del gráfico de confirmación general .
Siempre que hagamos que Git mire un nombre de rama como
master
, un nombre de etiqueta comov2.1
, o un nombre de seguimiento remoto comoorigin/master
, tendemos a querer que Git nos diga sobre esa confirmación. y cada confirmación a la que podemos llegar desde esa confirmación: comenzando allí y trabajando al revés.En matemáticas, esto se conoce como caminar por un gráfico . El gráfico de confirmación de Git es un gráfico acíclico dirigido o DAG , y este tipo de gráfico es especialmente adecuado para caminar. Al caminar por un gráfico de este tipo, se visitará cada vértice del gráfico al que se puede acceder a través del camino que se está utilizando. Los vértices en el gráfico de Git son las confirmaciones, y los bordes son arcos (enlaces unidireccionales) que van de cada hijo a cada padre. (Aquí es donde Think Like (a) Git entra . La naturaleza unidireccional de los arcos significa que Git debe funcionar al revés, de hijo a padre).
Los dos comandos principales de Git para recorrer gráficos son
git log
ygit rev-list
. Estos comandos son extremadamente similares, de hecho, en su mayoría están construidos a partir de los mismos archivos fuente, pero su salida es diferente:git log
produce una salida para que los humanos la lean, mientras quegit rev-list
produce una salida para que la lean otros programas Git. 1 Ambos comandos realizan este tipo de recorrido gráfico.El recorrido del gráfico que hacen es específicamente: dado un conjunto de confirmaciones de punto de partida (tal vez solo una confirmación, tal vez un montón de ID de hash, tal vez un montón de nombres que se resuelven en ID de hash), recorre el gráfico, visitando las confirmaciones . Directivas particulares, como
--not
o un prefijo^
, o--ancestry-path
, o--first-parent
, modifican el recorrido del gráfico de alguna manera.A medida que recorren el gráfico, visitan cada confirmación. Pero solo imprimen algunos subconjuntos seleccionados de las confirmaciones caminadas. Directivas como
--no-merges
o--before <date>
indican el código que recorre el gráfico que se compromete a imprimir .Para hacer esta visita, una confirmación a la vez, estos dos comandos usan una cola de prioridad . Ejecutas
git log
ogit rev-list
y le das algunas confirmaciones de punto de partida. Ponen esas confirmaciones en la cola de prioridad. Por ejemplo, un simple:convierte el nombre
master
en un ID de hash sin procesar y coloca ese ID de hash en la cola. O:convierte ambos nombres en ID de hash y, asumiendo que se trata de dos ID de hash diferentes, coloca ambos en la cola.
La prioridad de las confirmaciones en esta cola está determinada por aún más argumentos. Por ejemplo, el argumento
--author-date-order
le dice agit log
ogit rev-list
que use la marca de tiempo del autor , en lugar de la marca de tiempo del confirmador. El valor predeterminado es usar la marca de tiempo del confirmador y elegir el compromiso más reciente por fecha: el que tiene la fecha numérica más alta. Entoncesmaster develop
, suponiendo que se resuelvan en dos confirmaciones diferentes, Git mostrará la que vino más tarde primero, porque estará al principio de la cola.En cualquier caso, el código de revisión para caminar ahora se ejecuta en un bucle:
--no-merges
: no imprime nada si es una confirmación de fusión;--before
: no imprime nada si su fecha no es anterior a la hora designada. Si no se suprime la impresión, imprima la confirmación: paragit log
, muestre su registro; paragit rev-list
, imprime su ID de hash.--first-parent
suprime todos menos el primer padre de cada combinación.(Ambos
git log
ygit rev-list
pueden simplificar el historial con o sin reescritura de los padres en este punto también, pero lo omitiremos aquí).Para una cadena simple, como comenzar en
HEAD
y trabajar hacia atrás cuando no hay combinaciones de confirmaciones, la cola siempre tiene una confirmación en la parte superior del ciclo. Hay una confirmación, así que la sacamos, la imprimimos y ponemos su padre (único) en la cola y volvemos a dar la vuelta, y seguimos la cadena hacia atrás hasta que llegamos a la primera confirmación, o el usuario se cansa de lagit log
salida y se cierra. el programa. En este caso, ninguna de las opciones de pedido importa: solo hay una confirmación para mostrar.Cuando hay fusiones y seguimos a ambos padres, ambas "patas" de la fusión, o cuando otorgas
git log
ogit rev-list
más de una confirmación inicial, las opciones de clasificación son importantes.Por último, considere el efecto de un especificador de confirmación
--not
o^
delante de él. Estos tienen varias formas de escribirlos:o:
o:
todos significan lo mismo. El
--not
es como el prefijo^
excepto que se aplica a más de un nombre:significa no branch1, no branch2, sí branch3; pero:
significa que no es branch1, no branch2, no branch3, y tienes que usar un segundo
--not
para apagarlo:lo cual es un poco incómodo. Las dos directivas "no" se combinan a través de XOR, por lo que si realmente lo desea, puede escribir:
para significar no branch1, no branch2, sí branch3 , si quieres ofuscar .
Todos estos funcionan al afectar el recorrido del gráfico. Como
git log
ogit rev-list
paseos el gráfico, se asegura de no poner en la cola de prioridad ningún commit que es accesible desde cualquiera de los negados referencias. (De hecho, también afectan la configuración inicial: las confirmaciones negadas no pueden ir a la cola de prioridad directamente desde la línea de comando, por lo quegit log master ^master
no muestra nada, por ejemplo).Toda la elegante sintaxis descrita en la documentación de gitrevisions hace uso de esto, y puede exponerlo con una simple llamada a
git rev-parse
. Por ejemplo:La sintaxis de tres puntos significa que las confirmaciones se pueden alcanzar desde el lado izquierdo o derecho, pero excluyendo las confirmaciones accesibles desde ambos . En este caso , se puede acceder a la
origin/master
confirmaciónb34789c0b
,, desdeorigin/pu
(fc307aa37...
), por lo que elorigin/master
hash aparece dos veces, una vez con una negación, pero de hecho Git logra la sintaxis de tres puntos colocando dos referencias positivas (las dos ID de hash no negadas) y uno negativo, representado por el^
prefijo.Similarmente:
La
^@
sintaxis significa todos los padres de la confirmación dada , y élmaster^
mismo, el primer padre de la confirmación seleccionado por nombre de rama,master
es una confirmación de fusión, por lo que tiene dos padres. Estos son los dos padres. Y:El
^!
sufijo significa el compromiso en sí, pero ninguno de sus padres . En este caso,master^
es0b07eecf6...
. Ya vimos a ambos padres con el^@
sufijo; aquí están de nuevo, pero esta vez, negadas.1 Muchos programas de Git se ejecutan literalmente
git rev-list
con varias opciones y leen su salida para saber qué confirmaciones y / u otros objetos de Git usar.2 Debido a que el gráfico es acíclico , es posible garantizar que ninguno haya sido visitado ya, si agregamos la restricción nunca mostrar un padre antes de mostrar todos sus hijos a la prioridad.
--date-order
,--author-date-order
y--topo-order
agregue esta restricción. El orden de clasificación predeterminado, que no tiene nombre, no lo tiene. Si las marcas de tiempo de las confirmaciones son confusas, si, por ejemplo, algunas confirmaciones fueron realizadas "en el futuro" por una computadora cuyo reloj estaba apagado, esto podría en algunos casos conducir a resultados de apariencia extraña.Si llegaste tan lejos, ahora sabes mucho sobre
git log
Resumen:
git log
se trata de mostrar algunas confirmaciones seleccionadas mientras se recorre parte o la totalidad de alguna parte del gráfico.--no-merges
argumento, que se encuentra tanto en las respuestas aceptadas como en las mejor clasificadas actualmente, suprime la visualización de algunas confirmaciones que se caminan.--first-parent
argumento, de la respuesta actualmente mejor clasificada, suprime caminar algunas partes del gráfico, durante el recorrido del gráfico en sí.--not
prefijo a los argumentos de la línea de comandos, como se usa en la respuesta aceptada, suprime la visita a algunas partes del gráfico, desde el principio.Obtenemos las respuestas que nos gustan, a dos preguntas diferentes, utilizando estas funciones.
fuente