¿Cómo encontrar el padre más cercano de una sucursal de Git?

419

Digamos que tengo el siguiente repositorio local con un árbol de confirmación como este:

master --> a
            \
             \
      develop c --> d
               \
                \
         feature f --> g --> h

masteres mi este es el último código de lanzamiento estable , developes mi este es el "próximo" código de lanzamiento y featurees una nueva característica que se está preparandodevelop .

Lo que quiero poder hacer en mi repositorio remoto usando ganchos es featurerechazar los empujes a menos que commit fsea ​​un descendiente directo de developHEAD. es decir, el árbol de confirmación se ve así porque la función ha estado git rebaseactivada d.

master --> a
            \
             \
      develop c --> d
                     \
                      \
               feature f --> g --> h

Entonces, ¿es posible:

  • Identificar la rama principal de feature?
  • Identifique la confirmación en la rama principal de la que fes descendiente?

A partir de ahí, verificaría qué HEAD de la rama principal es, y vería si el fpredecesor coincide con el HEAD de la rama principal, para determinar si la característica necesita ser modificada.

Peter Farmer
fuente
esta pregunta debe reformularse para encontrar el padre de un padre.
Tim Boland,

Respuestas:

348

Suponiendo que el repositorio remoto tiene una copia de la rama de desarrollo (su descripción inicial lo describe en un repositorio local, pero parece que también existe en el remoto), debería poder lograr lo que creo que quiere, pero el enfoque es un poco diferente de lo que has imaginado.

La historia de Git se basa en un DAG de commits. Las ramas (y las "referencias" en general) son solo etiquetas transitorias que apuntan a compromisos específicos en el DAG de compromiso en continuo crecimiento. Como tal, la relación entre ramas puede variar con el tiempo, pero la relación entre confirmaciones no lo hace.

    ---o---1                foo
            \
             2---3---o      bar
                  \
                   4
                    \
                     5---6  baz

Parece que bazse basa en (una versión anterior de) bar? ¿Pero qué pasa si borramos bar?

    ---o---1                foo
            \
             2---3
                  \
                   4
                    \
                     5---6  baz

Ahora parece que bazse basa en foo. Pero la ascendencia de bazno cambió, simplemente eliminamos una etiqueta (y la confirmación pendiente resultante). ¿Y si agregamos una nueva etiqueta en 4?

    ---o---1                foo
            \
             2---3
                  \
                   4        quux
                    \
                     5---6  baz

Ahora parece que bazse basa en quux. Aún así, la ascendencia no cambió, solo cambiaron las etiquetas.

Sin embargo, si estuviéramos preguntando "¿es commit 6un descendiente de commit 3?" (suponiendo 3y 6son nombres de confirmación SHA-1 completos), la respuesta sería "sí", independientemente de si las etiquetas bary quuxestán presentes o no.

Por lo tanto, puede hacer preguntas como "¿el commit forzado es descendiente de la punta actual de la rama de desarrollo ?", Pero no puede preguntar de manera confiable "¿cuál es la rama padre del commit forzado?".

Una pregunta en su mayoría confiable que parece acercarse a lo que quieres es:

Para todos los ancestros del commit empujado (excluyendo la punta actual de desarrollo y sus antepasados), que tienen la punta actual de desarrollo como padre:

  • ¿existe al menos una de estas confirmaciones?
  • ¿son todos estos commits commits monoparentales?

Que podría implementarse como:

pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_children_of_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -F "$baserev"
)"
case ",$parents_of_children_of_base" in
    ,)     echo "must descend from tip of '$basename'"
           exit 1 ;;
    ,*\ *) echo "must not merge tip of '$basename' (rebase instead)"
           exit 1 ;;
    ,*)    exit 0 ;;
esac

Esto cubrirá algo de lo que desea restringir, pero tal vez no todo.

Como referencia, aquí hay un historial de ejemplo extendido:

    A                                   master
     \
      \                    o-----J
       \                  /       \
        \                | o---K---L
         \               |/
          C--------------D              develop
           \             |\
            F---G---H    | F'--G'--H'
                    |    |\
                    |    | o---o---o---N
                     \   \      \       \
                      \   \      o---o---P
                       \   \   
                        R---S

El código anterior podría ser utilizado para rechazar Hy Saceptando al mismo tiempo H', J, K, o N, pero sería también aceptar Ly P(que implican fusiones, pero no fusionar la punta del desarrollo ).

También a rechazar Ly P, puede cambiar la pregunta y pedir

Para todos los ancestros del commit empujado (excluyendo la punta actual de desarrollo y sus ancestros):

  • ¿Hay algún compromiso con dos padres?
  • en caso negativo, ¿tiene al menos una de estas confirmaciones la punta actual de desarrollar su (único) padre?
pushedrev=...
basename=develop
if ! baserev="$(git rev-parse --verify refs/heads/"$basename" 2>/dev/null)"; then
    echo "'$basename' is missing, call for help!"
    exit 1
fi
parents_of_commits_beyond_base="$(
  git rev-list --pretty=tformat:%P "$pushedrev" --not "$baserev" |
  grep -v '^commit '
)"
case "$parents_of_commits_beyond_base" in
    *\ *)          echo "must not push merge commits (rebase instead)"
                   exit 1 ;;
    *"$baserev"*)  exit 0 ;;
    *)             echo "must descend from tip of '$basename'"
                   exit 1 ;;
esac
Chris Johnsen
fuente
Me sale esto: git: fatal: argumento ambiguo '...': tanto revisión como nombre de archivo. ¿Cuál es la intención de los tres puntos?
Jack Ukleja
1
@Schneider Estoy bastante seguro de que '...' está destinado a ser un marcador de posición en este ejemplo: si lo reemplaza con el SHA de la confirmación, está intentando realizar esta verificación (por ejemplo, el HEAD de la sucursal actualmente estás en), todo funciona bien.
Daniel Brady
Gracias por esta elaborada respuesta! Es super útil. Quiero hacer un enlace similar, pero no quiero codificar el nombre de la rama de desarrollo. Lo que significa que quiero un gancho para evitar rebase a una rama que no sea la rama principal. Si entiendo bien tu respuesta (soy nuevo en bash y demás), esto no está cubierto en tu respuesta, ¿verdad? ¿Hay alguna forma de hacer esto?
Kemeia
¿Estás dispuesto a responder una pregunta relacionada? No pude hacer que tu código funcionara en un repositorio REMOTE. Aquí está el enlace a la pregunta de seguimiento sobre cómo adaptar su enfoque para trabajar con un repositorio REMOTO: stackoverflow.com/questions/49619492/…
CodeMed
Esto no funcionó para mí cuando lo tuve develop > release > feature, volvería a desarrollar y requiere conocer a los padres. La solución a mi problema fue stackoverflow.com/a/56673640/2366390
verdverm
241

Una reformulación

Otra forma de formular la pregunta es "¿Cuál es la confirmación más cercana que reside en una rama distinta de la rama actual, y qué rama es esa?"

Una solución

Puedes encontrarlo con un poco de magia de línea de comando

git show-branch \
| sed "s/].*//" \
| grep "\*" \
| grep -v "$(git rev-parse --abbrev-ref HEAD)" \
| head -n1 \
| sed "s/^.*\[//" 

Con awk :

git show-branch -a \
| grep '\*' \
| grep -v `git rev-parse --abbrev-ref HEAD` \
| head -n1 \
| sed 's/[^\[]*//' \
| awk 'match($0, /\[[a-zA-Z0-9\/-]+\]/) { print substr( $0, RSTART+1, RLENGTH-2 )}'

Así es como funciona:

  1. Muestra un historial textual de todas las confirmaciones, incluidas las ramas remotas.
  2. Los antepasados ​​del compromiso actual se indican con una estrella. Filtra todo lo demás.
  3. Ignora todos los commits en la rama actual.
  4. El primer resultado será la rama ancestral más cercana. Ignora los otros resultados.
  5. Los nombres de las ramas se muestran [entre paréntesis]. Ignora todo lo que está fuera de los corchetes y los corchetes.
  6. A veces, el nombre de la rama incluirá un ~ # o ^ # para indicar cuántas confirmaciones hay entre la confirmación referenciada y la punta de la rama. No nos importa Ingnóralos.

Y el resultado

Ejecutando el código anterior en

 A---B---D <-master
      \
       \
        C---E---I <-develop
             \
              \
               F---G---H <-topic

Te dará developsi lo ejecutas desde H y mastersi lo ejecutas desde I.

El código está disponible como una esencia

Joe Chrysler
fuente
24
Se eliminó un backtick final que causaba un error. Sin embargo, cuando ejecuto este comando, recibo una gran cantidad de advertencias, quejándome de que cada rama dicecannot handle more than 25 refs
Jon L.
1
@JoeChrysler, ¿cree que puede hacer que sea una línea en lugar de 2, y posiblemente hacer que funcione en Mac, ya ackque no está disponible en Mac (alguien sugirió reemplazar ackcon grep)
polaridad
53
Lo siento, esa es una incorrecta. Aquí está el correcto que funcionó para mí:git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'
droidbot
15
@droidbot Nice, pero necesita reordenar las tuberías para evitar la eliminación de referencias cuando grep -v catch commit message o el nombre de su sucursal es parte de otro nombre de sucursal. git show-branch | sed "s/].*//" | grep "\*" | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed "s/^.*\[//"
gaal
3
@OlegAbrazhaev No sé si alguna vez respondiste a tu pregunta. usando el alias git de: parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"funciona para mí
mduttondev
111

También puedes probar:

git log --graph --decorate
rcde0
fuente
55
git log --graph --decorate --simplify-by-decorationdonde --graphes opcional
Na13-c
1
git log --graph --decorate --simplify-by-decoration --oneline
anishtain4
106

git parent

Puedes simplemente ejecutar el comando

git parent

para encontrar el padre de la rama, si agrega la respuesta de @Joe Chrysler como un alias git . Simplificará el uso.

Abra el archivo gitconfig ubicado en "~/.gitconfig"cualquier editor de texto. (Para linux). Y para Windows, la ruta ".gitconfig" generalmente se encuentra enc:\users\your-user\.gitconfig

vim  ~/.gitconfig

Agregue el siguiente comando de alias en el archivo:

[alias]
            parent = "!git show-branch | grep '*' | grep -v \"$(git rev-parse --abbrev-ref HEAD)\" | head -n1 | sed 's/.*\\[\\(.*\\)\\].*/\\1/' | sed 's/[\\^~].*//' #"

Guarde y salga del editor.

Ejecuta el comando git parent

¡Eso es!

NIKHIL CM
fuente
55
Esta es una gran solución. Sería útil agregar también algunos resultados de muestra para garantizar los resultados esperados. Cuando lo ejecuté, recibí algunas advertencias antes de la última línea, que creo que era el nombre de la rama principal.
ttemple
44
¡Funciona de maravilla! Para los usuarios de Windows, el .gitconfig generalmente se encuentra en c: \ users \ your-user \ .gitconfig
zion el
12
Obteniendo cannot handle more than 25 refsexcepción.
shajin
¿Alguien puede editar esto para manejar la advertencia? @ttemple, ¿puedes?
NIKHIL CM
@NIKHILCM funciona como un campeón. Pero tengo una pregunta aquí si el padre indica desde dónde se creó la rama o algo más.
Hariprasath
52

Tengo una solución a su problema general (determine si featuredesciende de la punta dedevelop ), pero no funciona utilizando el método que describió.

Puede usar git branch --containspara enumerar todas las ramas que descienden de la punta de develop, luego use greppara asegurarse de que featureesté entre ellas.

git branch --contains develop | grep "^ *feature$"

Si está entre ellos, imprimirá " feature"a la salida estándar y tendrá un código de retorno de 0. De lo contrario, no imprimirá nada y tendrá un código de retorno de 1.

Daniel Stutzbach
fuente
1
Esto funciona, pero debe tenerse en cuenta que puede llevar mucho tiempo en un repositorio que tiene muchas referencias. Eso lo hace un poco menos que ideal para correr, por ejemplo, un gancho previo a la recepción.
Ebneter
Estaba buscando la sucursal, la llamaremos <branch>, donde realicé: git checkout -b <branch-2>desde ... ¡ESTA es la respuesta! No hay necesidad de grep, de verdad. git branch --contains <branch>
Poopy McFartnoise
44

Esto funciona bien para mí.

git show-branch | grep '*' | grep -v "$(git rev-parse --abbrev-ref HEAD)" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Respuestas de cortesía de: @droidbot y @Jistanidiot

Murali Mopuru
fuente
Sí, pero a veces te da "tubería rota" de grep.
Vladislav Rastrusny
1
*no es una expresión regular adecuada para pasar a grep. Debería usar grep -F '*'o en su grep '\*'lugar. Buena solución de lo contrario.
arielf
No tengo salida.
Sandip Subedi
funciona para mí ....
roottraveller
11

Como ninguna de las respuestas anteriores funcionó en nuestro repositorio, quiero compartir mi propio camino, utilizando las últimas fusiones en git log:

#!/bin/bash
git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 10

Póngalo en un script llamado git-last-merges, que también acepta un nombre de rama como argumento (en lugar de la rama actual), así como otrosgit log argumentos

A partir de la salida, podemos detectar manualmente la (s) rama (s) principal (es) en función de las convenciones de ramificación propias y el número de fusiones de cada rama.

EDITAR: si usa git rebaseen ramas secundarias a menudo (y las fusiones se reenvían rápidamente a menudo para que no haya demasiados commits de fusión), esta respuesta no funcionará bien, así que escribí un script para contar los commits por adelantado (normal y merge) , y detrás de confirmaciones (no debería haber ninguna fusión posterior en la rama principal) en todas las ramas en comparación con la rama actual. Simplemente ejecute este script y avíseme si funciona para usted o no

#!/bin/bash
HEAD="`git rev-parse --abbrev-ref HEAD`"
echo "Comparing to $HEAD"
printf "%12s  %12s   %10s     %s\n" "Behind" "BehindMerge" "Ahead" "Branch"
git branch | grep -v '^*' | sed 's/^\* //g' | while read branch ; do
    ahead_merge_count=`git log --oneline --merges $branch ^$HEAD | wc -l`
    if [[ $ahead_merge_count != 0 ]] ; then
        continue
    fi
    ahead_count=`git log --oneline --no-merges $branch ^$HEAD | wc -l`
    behind_count=`git log --oneline --no-merges ^$branch $HEAD | wc -l`
    behind_merge_count=`git log --oneline --merges ^$branch $HEAD | wc -l`
    behind="-$behind_count"
    behind_merge="-M$behind_merge_count"
    ahead="+$ahead_count"
    printf "%12s  %12s   %10s     %s\n" "$behind" "$behind_merge" "$ahead" "$branch"
done | sort -n
saeedgnu
fuente
Gracias. Aunque esto puede no funcionar muy bien si lo usa con rebasefrecuencia (y las fusiones se fast-forwardeditan con frecuencia). Editaré mi respuesta si encuentro una mejor solución.
saeedgnu
1
¿Lo único? respuesta hasta ahora que funcionó de manera sensata para mí en el caso donde la rama actual es maestra. La mayoría de las otras soluciones dieron un resultado aleatorio (y claramente incorrecto) en este caso de borde donde no hay ramas principales reales.
arielf
Esta es la única respuesta que funcionó para mí. Para obtener el primer padre en lugar de una lista de los primeros 10 puede usar esto: git log --oneline --merges "$@" | grep into | sed 's/.* into //g' | uniq --count | head -n 1 | cut -d ' ' -f 8
lots0logs
10

Una solución

La solución basada engit show-branch no funcionó para mí (ver más abajo), así que la combiné con la que estaba basadagit log y terminé con esto:

git log --decorate --simplify-by-decoration --oneline \ # selects only commits with a branch or tag
      | grep -v "(HEAD" \                               # removes current head (and branch)
      | head -n1 \                                      # selects only the closest decoration
      | sed 's/.* (\(.*\)) .*/\1/' \                    # filters out everything but decorations
      | sed 's/\(.*\), .*/\1/' \                        # picks only the first decoration
      | sed 's/origin\///'                              # strips "origin/" from the decoration

Limitaciones y advertencias

  • HEAD se puede separar (muchas herramientas de CI lo hacen para asegurarse de que crean la confirmación correcta en una rama determinada), pero la rama de origen y la rama local deben estar a la par o "arriba" la HEAD actual.
  • No debe haber etiquetas en el camino (supongo; no he probado el script en commits con una etiqueta entre la rama secundaria y la secundaria)
  • el guion se basa en el hecho de que "HEAD" siempre aparece como la primera decoración por el logcomando
  • ejecutar la secuencia de comandos en masterydevelop resultados (en su mayoría) en<SHA> Initial commit

Los resultados

 A---B---D---E---F <-origin/master, master
      \      \
       \      \
        \      G---H---I <- origin/hotfix, hotfix
         \
          \
           J---K---L <-origin/develop, develop
                \
                 \
                  M---N---O <-origin/feature/a, feature/a
                       \   \
                        \   \
                         \   P---Q---R <-origin/feature/b, feature/b
                          \
                           \
                            S---T---U <-origin/feature/c, feature/c

A pesar de la existencia de una sucursal local (por ejemplo, solo origin/topicestá presente desde que el OSHA desprotegió la confirmación directamente), el script debe imprimirse de la siguiente manera:

  • Para las confirmaciones G, H,I (rama hotfix) →master
  • Para las confirmaciones M, N,O (rama feature/a) →develop
  • Para las confirmaciones S, T,U (rama feature/c) →develop
  • Para las confirmaciones P, Q,R (rama feature/b) →feature/a
  • Para las confirmaciones J, K, L(rama develop) → <sha> Initial commit*
  • Para las confirmaciones B, D, E, F(rama master) →<sha> Initial commit

* - o mastersi developlos commits estuvieran encima del HEAD del master (~ el master sería rápido de desarrollar)


¿Por qué no me funcionó la sucursal?

La solución basada engit show-branch demostró ser poco confiable para mí en las siguientes situaciones:

  • CABEZA separada : ¡incluir la caja de cabeza separada significa reemplazar grep '\*' \por 'grep'! \ - y eso es solo el comienzo de todos los problemas
  • ejecutar la secuencia de comandos en masterydevelop resultados en developy `` respectivamente
  • Las ramas enmaster rama ( hotfix/ramas) terminan con el developcomo padre ya que su masterpadre de rama más cercano se marcó con en !lugar de *por una razón.
Matt Stuvysant
fuente
2
Única respuesta que trabajó - como un alias de git:"!git log --decorate --simplify-by-decoration --oneline | grep -v '(HEAD' | head -n1 | sed 's/.* (\\(.*\\)) .*/\\1/' | sed 's/\\(.*\\), .*/\\1/' | sed 's/origin\\///'"
Ian Kemp
8

Recuerde que, como se describe en "Git: Encontrar de qué rama proviene un commit" , no puede identificar fácilmente la rama donde se realizó ese commit (las ramas se pueden renombrar, mover, eliminar ...), aunque git branch --contains <commit>sea ​​un comienzo.

  • Puede volver de commit a commit hasta git branch --contains <commit>que no enumere la featurerama y la lista de developramas,
  • compara ese commit SHA1 con /refs/heads/develop

Si los dos commits coinciden con la identificación, está listo (eso significaría que la featurerama tiene su origen en HEAD of develop).

VonC
fuente
6

La magia de la línea de comandos de JoeChrysler se puede simplificar. Aquí está la lógica de Joe: por brevedad, he introducido un parámetro nombrado cur_branchen lugar de la sustitución del comando `git rev-parse --abbrev-ref HEAD`en ambas versiones; que se puede inicializar así:

cur_branch=$(git rev-parse --abbrev-ref HEAD)

Entonces, aquí está la tubería de Joe:

git show-branch -a           |
  grep '\*'                  | # we want only lines that contain an asterisk
  grep -v "$cur_branch"      | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed

Podemos lograr lo mismo que los cinco filtros de comandos individuales en un awkcomando relativamente simple :

git show-branch -a |
  awk -F'[]^~[]' '/\*/ && !/'"$cur_branch"'/ {print $2;exit}'  

Eso se descompone así:

-F'[]^~[]' 

dividir la línea en los campos de ], ^, ~, y [caracteres.

/\*/                      

Encuentra líneas que contienen un asterisco

&& !/'"$cur_branch"'/

... pero no el nombre de la sucursal actual

{ print $2;               

Cuando encuentre dicha línea, imprima su segundo campo (es decir, la parte entre la primera y la segunda aparición de nuestros caracteres separadores de campo). Para nombres de rama simples, eso será justo lo que está entre los corchetes; para referencias con saltos relativos, será solo el nombre sin el modificador. Entonces, nuestro conjunto de separadores de campo maneja la intención de ambos sedcomandos.

  exit }

Luego salga de inmediato. Esto significa que solo procesa la primera línea coincidente, por lo que no necesitamos canalizar la salida head -n 1.

Mark Reed
fuente
3
Tenga en cuenta que algunas ramas pueden faltar en la salida debido a demasiadas referencias. En su lugar, se muestran como advertencias en stderr.
Zitrax
5

Aquí hay una implementación de PowerShell de la solución de Mark Reed:

git show-branch -a | where-object { $_.Contains('*') -eq $true} | Where-object {$_.Contains($branchName) -ne $true } | select -first 1 | % {$_ -replace('.*\[(.*)\].*','$1')} | % { $_ -replace('[\^~].*','') }
Chrisevett
fuente
5

No digo que esta sea una buena manera de resolver este problema, sin embargo, esto parece funcionar para mí.

git branch --contains $(cat .git/ORIG_HEAD) El problema es que la captura de un archivo se asoma al funcionamiento interno de git, por lo que esto no es necesariamente compatible con versiones anteriores (o compatibles con versiones anteriores).

usuario1529413
fuente
3

Implementación multiplataforma con Ant

    <exec executable="git" outputproperty="currentBranch">
        <arg value="rev-parse" />  
        <arg value="--abbrev-ref" />  
        <arg value="HEAD" />  
    </exec>

    <exec executable="git" outputproperty="showBranchOutput">
        <arg value="show-branch" />  
        <arg value="-a" />  
    </exec>

    <loadresource property="baseBranch">
      <propertyresource name="showBranchOutput"/>
          <filterchain>
            <linecontains>
              <contains value="*"/>
            </linecontains>
            <linecontains negate="true">
              <contains value="${currentBranch}"/>
            </linecontains>
            <headfilter lines="1"/>
            <tokenfilter>
                <replaceregex pattern=".*\[(.*)\].*" replace="\1"/>
                <replaceregex pattern="[\^~].*" replace=""/>
            </tokenfilter>
          </filterchain>
    </loadresource>

    <echo message="${currentBranch} ${baseBranch}" />
ENargit
fuente
2

@ Mark Reed: ¡Debe agregar que la línea de confirmación no solo debe contener un asterisco, sino que debe comenzar con un asterisco! De lo contrario, los mensajes de confirmación que contienen un asterisco también se incluyen en las líneas coincidentes. Entonces debería ser:

git show-branch -a | awk -F'[]^~[]' '/^\*/ && !/'"$current_branch"'/ {print $2;exit}'

o la versión larga:

git show-branch -a           |
  awk '^\*'                  | # we want only lines that contain an asterisk
  awk -v "$current_branch"   | # but also don't contain the current branch
  head -n1                   | # and only the first such line
  sed 's/.*\[\(.*\)\].*/\1/' | # really, just the part of the line between []
  sed 's/[\^~].*//'            # and with any relative refs (^, ~n) removed`
ladiko
fuente
2
vbc=$(git rev-parse --abbrev-ref HEAD)
vbc_col=$(( $(git show-branch | grep '^[^\[]*\*' | head -1 | cut -d* -f1 | wc -c) - 1 )) 
swimming_lane_start_row=$(( $(git show-branch | grep -n "^[\-]*$" | cut -d: -f1) + 1 )) 
git show-branch | tail -n +$swimming_lane_start_row | grep -v "^[^\[]*\[$vbc" | grep "^.\{$vbc_col\}[^ ]" | head -n1 | sed 's/.*\[\(.*\)\].*/\1/' | sed 's/[\^~].*//'

Logra los mismos fines que la respuesta de Mark Reed, pero utiliza un enfoque mucho más seguro que no se comporta mal en una serie de escenarios:

  1. La última confirmación de la rama principal es una fusión, lo que hace que la columna muestre - no*
  2. El mensaje de confirmación contiene el nombre de la sucursal
  3. El mensaje de confirmación contiene *
Haoyang Feng
fuente
0

Cualquiera que quiera hacer esto en estos días: la aplicación SourceTree de Atlassian le muestra una excelente representación visual de cómo sus ramas se relacionan entre sí, es decir, dónde comenzaron y dónde se encuentran actualmente en el orden de compromiso (por ejemplo, HEAD o 4 commits detrás, etc.) .

jake
fuente
0

Si utiliza el Árbol de fuentes, consulte los detalles de confirmación> Padres> y verá los números de confirmación subrayados (enlaces)

Mike6679
fuente
0

Una alternativa: git rev-list master | grep "$(git rev-list HEAD)" | head -1

Obtenga la última confirmación de que es mi rama y master(o cualquier rama que desee especificar)

Alexander Woods
fuente
0

Esto no funcionó para mí cuando había hecho algo como develop > release-v1.0.0 > feature-foo, volvería a desarrollarse, tenga en cuenta que hubo un rebase involucrado, no estoy seguro de si eso está agravando mi problema ...

Lo siguiente dio el hash de confirmación correcto para mí

git log --decorate \
  | grep 'commit' \
  | grep 'origin/' \
  | head -n 2 \
  | tail -n 1 \
  | awk '{ print $2 }' \
  | tr -d "\n"
verdverm
fuente