Git log para obtener confirmaciones solo para una rama específica

214

Quiero enumerar todas las confirmaciones que son solo parte de una rama específica.

Con lo siguiente, enumera todos los commits de la rama, pero también del padre (maestro)

git log mybranch

La otra opción que encontré fue excluir los commits accesibles por master y me da lo que quiero, PERO me gustaría evitar la necesidad de conocer los nombres de otras ramas.

git log mybranch --not master

Estaba tratando de usar git for-each-ref, pero también está enumerando mybranch, por lo que en realidad está excluyendo todo:

git log mybranch --not $(git for-each-ref --format '^%(refname:short)' refs/heads/)

Actualizar:

Estoy probando una nueva opción que encontré hace un tiempo, y hasta ahora parece que esto podría ser lo que estaba buscando:

git log --walk-reflogs mybranch

Actualización (2013-02-13T15: 08):

La opción --walk-reflogs es buena, pero verifiqué que hay una caducidad para los reflogs (por defecto 90 días, gc.reflogExpire ).

Creo que encontré la respuesta que estaba buscando:

git log mybranch --not $(git for-each-ref --format='%(refname)' refs/heads/ | grep -v "refs/heads/mybranch")

Solo estoy eliminando la rama actual de la lista de ramas disponibles y estoy usando esa lista para excluirla del registro. De esta manera solo obtengo los commits que solo mybranch alcanza .

dimirc
fuente
posible duplicado con stackoverflow.com/questions/53569
StarPinkER
Ya vi esa pregunta también, pero no la misma
dimirc
2
¿Estás seguro de que eso es lo que quieres? Creo que es mejor tener un objetivo en mente: "lo que hay en mi rama que no está en la parte superior" o "lo que hay en mi rama que no está en el maestro". Además, aunque git es rápido en la poda, esto se volverá más costoso a medida que tenga más ramas. Tengo un script que uso que llamo "git missing" después del comando "missing" de bzr. Puede encontrarlo aquí: github.com/jszakmeister/etc/blob/master/git-addons/git-missing .
John Szakmeister
1
De hecho, necesito esto para un gancho posterior a la recepción, por lo que "maestro" no siempre será la rama para excluir
dimirc
Sí, el duplicado mencionado por StarPinkER funcionó bien para mí: git log $ (git merge-base HEAD branch) .. branch
charo

Respuestas:

165

Por lo que parece que deberías estar usando cherry:

git cherry -v develop mybranch

Esto mostraría todos los commits que están contenidos dentro de mybranch , pero NO en desarrollo . Si deja la última opción ( mybranch ), comparará la rama actual en su lugar.

Como señaló VonC, SIEMPRE está comparando su rama con otra rama, así que conozca sus ramas y luego elija con cuál comparar.

Smilie
fuente
44
Esto es exactamente lo que necesitaba, pero parece que debería haber un comando más intuitivo (sí, incluso en el mundo de Git) para esto.
Seth
12
También puede hacer git cherry -v masterpara comparar su rama actual con la rama maestra.
Pithikos
2
El peligro de usar git cherry es que las confirmaciones solo coinciden si sus diferencias de archivo son idénticas entre las ramas. Si se hizo algún tipo de fusión que haría que las diferencias fueran diferentes entre una rama y la otra, entonces git cherry las ve como confirmaciones diferentes.
Ben
Esto solo me da fatal: Unknown commit mybranch.
Matt Arnold
1
@MattArnold, debe cambiar el texto "desarrollar" y "mybranch" a ramas que existen en su repositorio
Smilie
40

PERO me gustaría evitar la necesidad de conocer los nombres de otras ramas.

No creo que esto sea posible: una rama en Git siempre se basa en otra o al menos en otra confirmación, como se explica en " git diff no muestra lo suficiente ":

ingrese la descripción de la imagen aquí

Necesita un punto de referencia para que su registro muestre los commits correctos.

Como se menciona en " GIT - ¿De dónde me ramifiqué? ":

las ramas son simplemente punteros a ciertas confirmaciones en un DAG

Entonces, incluso si git log master..mybranches una respuesta, aún mostraría demasiados commits, si mybranchse basa en myotherbranchsí mismo master.

Para encontrar esa referencia (el origen de su rama), solo puede analizar las confirmaciones y ver en qué rama están, como se ve en:

VonC
fuente
26

Finalmente encontré la manera de hacer lo que quería el OP. Es tan simple como:

git log --graph [branchname]

El comando mostrará todas las confirmaciones a las que se puede acceder desde la rama proporcionada en el formato de gráfico. Pero puede filtrar fácilmente todas las confirmaciones en esa rama mirando el gráfico de confirmaciones cuyo *es el primer carácter en la línea de confirmación.

Por ejemplo, echemos un vistazo al extracto de git log --graph masterrepositorio de GitHub de cakephp a continuación:

D:\Web Folder\cakephp>git log --graph master
*   commit 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4
|\  Merge: c3f45e8 0459a35
| | Author: José Lorenzo Rodríguez <[email protected]>
| | Date:   Tue Aug 30 08:01:59 2016 +0200
| |
| |     Merge pull request #9367 from cakephp/fewer-allocations
| |
| |     Do fewer allocations for simple default values.
| |
| * commit 0459a35689fec80bd8dca41e31d244a126d9e15e
| | Author: Mark Story <[email protected]>
| | Date:   Mon Aug 29 22:21:16 2016 -0400
| |
| |     The action should only be defaulted when there are no patterns
| |
| |     Only default the action name when there is no default & no pattern
| |     defined.
| |
| * commit 80c123b9dbd1c1b3301ec1270adc6c07824aeb5c
| | Author: Mark Story <[email protected]>
| | Date:   Sun Aug 28 22:35:20 2016 -0400
| |
| |     Do fewer allocations for simple default values.
| |
| |     Don't allocate arrays when we are only assigning a single array key
| |     value.
| |
* |   commit c3f45e811e4b49fe27624b57c3eb8f4721a4323b
|\ \  Merge: 10e5734 43178fd
| |/  Author: Mark Story <[email protected]>
|/|   Date:   Mon Aug 29 22:15:30 2016 -0400
| |
| |       Merge pull request #9322 from cakephp/add-email-assertions
| |
| |       Add email assertions trait
| |
| * commit 43178fd55d7ef9a42706279fa275bb783063cf34
| | Author: Jad Bitar <[email protected]>
| | Date:   Mon Aug 29 17:43:29 2016 -0400
| |
| |     Fix `@since` in new files docblocks
| |

Como se puede ver, sólo compromete 8314c2ff833280bbc7102cb6d4fcf62240cd3ac4y c3f45e811e4b49fe27624b57c3eb8f4721a4323btener el *ser el primer carácter de la confirmación líneas. Esas confirmaciones son de la rama maestra, mientras que las otras cuatro son de otras ramas.

Lukman
fuente
11

El siguiente comando de shell debe hacer lo que quieras:

git log --all --not $(git rev-list --no-walk --exclude=refs/heads/mybranch --all)

Advertencias

Si ha mybranchdesprotegido, el comando anterior no funcionará. Esto se debe a que mybranchtambién se puede HEADacceder a los commits, por lo que Git no considera que los commits sean únicos mybranch. Para que funcione cuando mybranchestá desprotegido, también debe agregar una exclusión para HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD \
    --all)

Sin embargo, debe no excluir HEADa menos que la mybranchestá desprotegido, de lo contrario se corre el riesgo mostrando compromete a que no son exclusivos demybranch .

Del mismo modo, si tiene una rama remota llamada origin/mybranchque corresponde a la mybranchrama local , deberá excluirla:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --all)

Y si la rama remota es la rama predeterminada para el repositorio remoto (generalmente solo es cierto para origin/master), también deberá excluir origin/HEAD:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Si tiene la rama desprotegida, y hay una rama remota, y la rama remota es la predeterminada para el repositorio remoto, entonces termina excluyendo mucho:

git log --all --not $(git rev-list --no-walk \
    --exclude=refs/heads/mybranch \
    --exclude=HEAD
    --exclude=refs/remotes/origin/mybranch \
    --exclude=refs/remotes/origin/HEAD \
    --all)

Explicación

El git rev-listcomando es un comando de bajo nivel (plomería) que recorre las revisiones dadas y vuelca los identificadores SHA1 encontrados. Piense en ello como equivalente a git logexcepto que solo muestra el SHA1: sin mensaje de registro, sin nombre de autor, sin marca de tiempo, ninguna de esas cosas "elegantes".

La --no-walkopción, como su nombre lo indica, evita git rev-listcaminar por la cadena de ascendencia. Entonces, si escribe git rev-list --no-walk mybranch, solo imprimirá un identificador SHA1: el identificador de la confirmación de propinas de la mybranchrama.

Los --exclude=refs/heads/mybranch --allargumentos le dicen git rev-listque comience desde cada referencia, excepto para refs/heads/mybranch.

Entonces, cuando ejecutas git rev-list --no-walk --exclude=refs/heads/mybranch --all, Git imprime el identificador SHA1 de la confirmación de propinas de cada referencia a excepción de refs/heads/mybranch. Estas confirmaciones y sus antepasados ​​son las confirmaciones en las que no está interesado; estas son las confirmaciones que no desea ver.

Las otras confirmaciones son las que desea ver, por lo que recopilamos el resultado git rev-list --no-walk --exclude=refs/heads/mybranch --ally le decimos a Git que muestre todo menos esas confirmaciones y sus antepasados.

El --no-walkargumento es necesario para repositorios grandes (y es una optimización para repositorios pequeños): sin él, Git tendría que imprimir, y el shell tendría que recopilar (y almacenar en la memoria) muchos más identificadores de confirmación de los necesarios. Con un repositorio grande, el número de confirmaciones recopiladas podría superar fácilmente el límite de argumento de la línea de comandos del shell.

Git bug?

Hubiera esperado que funcionara lo siguiente:

git log --all --not --exclude=refs/heads/mybranch --all

Pero no lo hace. Supongo que esto es un error en Git, pero tal vez sea intencional.

Richard Hansen
fuente
Buena explicación +1
VonC
55
Vine aquí queriendo saber cómo hacer Mercurial hg log -b <branch>. No entiendo por qué la gente dice que Git es hostil. / s
weberc2
No sé por qué git log --all --not --exclude=refs/heads/mybranch --allno funciona, pero git log refs/heads/mybranch --not --exclude=refs/heads/mybranch --allfunciona, con las mismas advertencias sobre excluir HEAD y origen.
Ben C
8

Respuesta rápida:

git log $(git merge-base master b2)..HEAD

Digamos:

  1. Que tienes una rama maestra

  2. Haz algunas confirmaciones

  3. Creaste una rama llamada b2

  4. Hacer git log -n1; el commit id es la base de fusión entre b2 y master

  5. Haz algunas confirmaciones en b2

  6. git log mostrará su historial de registro de b2 y master

  7. Use el rango de confirmación, si no está familiarizado con el concepto, lo invito a buscarlo en Google o apilarlo,

    Para su contexto real, puede hacer por ejemplo

    git log commitID_FOO..comitID_BAR
    

    El ".." es el operador de rango para el comando de registro.

    Eso significa, en una forma simple, darme todos los registros más recientes que commitID_FOO ...

  8. Mira el punto 4, la base de fusión

    Entonces: git log COMMITID_mergeBASE..HEADte mostrará la diferencia

  9. Git puede recuperar la base de fusión para ti así

    git merge-base b2 master
    
  10. Finalmente puedes hacer:

    git log $(git merge-base master b2)..HEAD
    
Frederic Nault
fuente
4

Podrías probar algo como esto:

#!/bin/bash

all_but()
{
    target="$(git rev-parse $1)"
    echo "$target --not"
    git for-each-ref --shell --format="ref=%(refname)" refs/heads | \
    while read entry
    do
        eval "$entry"

        test "$ref" != "$target" && echo "$ref"
    done
}

git log $(all_but $1)

O, tomando prestado de la receta en el Manual del usuario de Git :

#!/bin/bash
git log $1 --not $( git show-ref --heads | cut -d' ' -f2 | grep -v "^$1" )
John Szakmeister
fuente
+1. Estaba escribiendo en mi respuesta que necesita analizar las confirmaciones para encontrar el origen de su rama, y ​​parece que lo hizo.
VonC
¿Has utilizado log --walk-reflogs? Estoy leyendo sobre esta opción y me está dando los resultados que necesito hasta ahora, (todavía
estoy
@dimirc Reflogs son una bestia diferente todos juntos. Registra puntos de ramificación a lo largo del tiempo, generalmente con fines de recuperación. No estoy seguro de lo que está haciendo en su gancho posterior a la recepción, pero tal vez si lo explicara, la gente podría proporcionar una respuesta más sensata a su problema.
John Szakmeister
Solo necesito analizar / verificar todos los mensajes de confirmación de una vez. El caso que quiero cubrir es si alguien empuja múltiples commits en master y crea una nueva rama con múltiples commits también. El gancho posterior a la recepción debe verificar los cambios realizados para ambas referencias / sucursales, por ejemplo master y newbranch, necesito conocer los límites de la nueva sucursal para evitar analizar dos veces los mensajes de confirmación, ya que podría confirmarse desde master.
dimirc
1
Bueno. Entonces creo que el enfoque anterior que describí realmente es lo que quieres. Con reflog, las entradas se caerán después de un período de tiempo, y creo que eso le causará algunos dolores de cabeza. Es posible que desee ver el uso git show-ref --tagstambién.
John Szakmeister
4
git rev-list --exclude=master --branches --no-walk

enumerará los consejos de cada rama que no lo es master.

git rev-list master --not $(git rev-list --exclude=master --branches --no-walk)

enumerará todas las confirmaciones en masterel historial que no están en el historial de ninguna otra rama.

La secuencia es importante para las opciones que configuran la tubería de filtro para la selección de confirmación, por lo que --branchesdebe seguir los patrones de exclusión que se supone que debe aplicar, y --no-walkdebe seguir los filtros que suministran las confirmaciones que se supone que la lista de revoluciones no debe seguir.

jthill
fuente
4

Esto generará los commits en la rama actual. Si se pasa algún argumento, solo genera los hashes.

git_show_all_commits_only_on_this_branch

#!/bin/bash
function show_help()
{
  ME=$(basename $0)
  IT=$(cat <<EOF
  
  usage: $ME {NEWER_BRANCH} {OLDER_BRANCH} {VERBOSE}
  
  Compares 2 different branches, and lists the commits found only 
  in the first branch (newest branch). 

  e.g. 
  
  $ME         -> default. compares current branch to master
  $ME B1      -> compares branch B1 to master
  $ME B1 B2   -> compares branch B1 to B2
  $ME B1 B2 V -> compares branch B1 to B2, and displays commit messages
  
  )
  echo "$IT"
  exit
}

if [ "$1" == "help" ]
then
  show_help
fi

# Show commit msgs if any arg passed for arg 3
if [ "$3" ]
then
  OPT="-v"
fi

# get branch names
OLDER_BRANCH=${2:-"master"}
if [ -z "$1" ]
then
  NEWER_BRANCH=$(git rev-parse --abbrev-ref HEAD)
else
  NEWER_BRANCH=$1
fi

if [ "$NEWER_BRANCH" == "$OLDER_BRANCH" ]
then
  echo "  Please supply 2 different branches to compare!"
  show_help
fi

OUT=$(\git cherry $OPT $OLDER_BRANCH $NEWER_BRANCH)

if [ -z "$OUT" ]
then
  echo "No differences found. The branches $NEWER_BRANCH and $OLDER_BRANCH are in sync."
  exit;
fi

if [ "$OPT" == "-v" ]
then
  echo "$OUT"
else
  echo "$OUT" | awk '{print $2}'
fi
Brad Parks
fuente
1
Esto produjo alrededor de 100 mensajes de registro irrelevantes para mí.
Arlie Stephens
Hola @ArlieStephens. ¿Lo probé y me pareció que todavía funcionaba? Acabo de agregar ayuda y más mensajes de error a lo anterior. ¡Déjame saber como va!
Brad Parks
Interesante. Mirando el código como lo tiene ahora, creo que puede ser tan simple como el original, suponiendo que la rama que me importa salió del maestro. Con el código actual, podría haber especificado la rama principal explícitamente. (IIRC, mi rama de desarrollo vino de una rama de lanzamiento, no maestra.)
Arlie Stephens
@ArlieStephens: sí, no creo que haya cambiado ninguna funcionalidad ... Lo actualicé una vez más e hice los documentos un poco más exactos después de algunas pruebas locales ... y agregué una opción "detallada" que estaba allí antes, pero no lo hice
Brad Parks
3

Estoy usando los siguientes comandos:

git shortlog --no-merges --graph --abbrev-commit master..<mybranch>

o

git log --no-merges --graph --oneline --decorate master..<mybranch>
Alex
fuente
1

Encontré este enfoque relativamente fácil.

Pago a la sucursal y que

  1. correr

    git rev-list --simplify-by-decoration -2 HEAD
    

Esto proporcionará solo dos SHA:

1) última confirmación de la rama [C1]

2) y comprometer padre a la primera confirmación de la rama [C2]

  1. Ahora corre

    git log --decorate --pretty=oneline --reverse --name-status <C2>..<C1>
    

Aquí C1 y C2 son dos cadenas que obtendrá cuando ejecute el primer comando. Ponga estos valores sin <> en el segundo comando.

Esto le dará una lista del historial de cambios de archivos dentro de la rama.

Mustkeem K
fuente
Si usted lee las tres primeras líneas de la cuestión, verá que las listas de autor de este comando exacto y explica por qué no es lo que están buscando
black_fm
Ah @black_fm Hice algunos cambios en la respuesta. Puede votarlo si lo encuentra útil ahora. :)
Mustkeem K
0

En mi situación, estamos usando Git Flow y GitHub. Todo lo que necesita hacer es: comparar su rama de características con su rama de desarrollo en GitHub.

Mostrará las confirmaciones realizadas solo en su rama de características.

Por ejemplo:

https://github.com/your_repo/compare/develop...feature_branch_name

Peterpengnz
fuente
Estoy de acuerdo en que cuando entras en la situación "Quiero ver cómo se verá una solicitud de extracción", la mejor solución a menudo es ignorar gity en su lugar usar GitHub para hacer una solicitud de extracción o comparar las ramas.
pkamb