¿Cómo puedo ver de qué twig se bifurcó otra twig?

Mi repository git tiene tres twigs, devel , stable y customers/acme_patches . Hace mucho time, el stable se bifurcaba desde el devel , y toda la corrección de errores se realiza en forma stable . De vez en cuando, stable se fusiona de nuevo en devel . customers/acme_patches es una twig con algunos parches específicos del cliente. La twig no se fusionó ni en devel ni en stable .

Un poco de arte ASCII para ilustrar el escenario:

             o --- o --- o clientes / acme_patches?
            /
   o --- o --- 1 --- o --- o --- o estable
  / \ \
 o --- o --- o --- 2 --- o --- o --- o --- o devel
              \
               o --- o --- o clientes / acme_patches?

Ahora me pregunto:

¿De qué twig se customers/acme_patches de – devel o stable ? Solo sé que se bifurcó con uno de ellos en el pasado, pero no sé cuál. Por ejemplo, podría haber cometido 1 o 2 en el diagtwig anterior.

He estado jugando con git log --oneline --graph y gitk pero como customers/acme_patches se bifurcó hace unos cientos de commits, es difícil seguir las líneas que se dibujan.

¿Existe quizás un command rápido (un pequeño script también está bien) que de alguna manera puede seguir las confirmaciones en customers/acme_patches hacia atrás para encontrar el primer compromiso con dos hijos (el punto de bifurcación) y luego determina si ese compromiso se realizó en stable o en devel ?

En el mejor de los casos, podría ejecutar algo como (disculpe el post, estoy en Windows):

 C:\src> git fork-origin customers/acme_patches stable 

Bueno, probablemente no haya una solución perfecta para esta respuesta. Quiero decir que no hay equivalente de fork-origin en git (que yo sepa). Debido a que la twig stable se fusiona en devel , sus acme_patches (de 1) están en devel y twig stable .

Lo que podrías hacer es:

 git branch --contains $(git merge-base customers/acme_patches devel stable) 

Si tienes estabilidad y no desarrollo, o desarrollo y no es estable, entonces sabes de dónde viene.

Por ejemplo, en el caso 2, tendrías

 $ git branch --contains $(git merge-base customers/acme_patches devel stable) customers/acme_patches devel 

mientras que en el caso 1 tendrías

 $ git branch --contains $(git merge-base customers/acme_patches devel stable) customers/acme_patches devel stable 

Como ahora está en ambas twigs (debido a la combinación de estable a dev)

Con git 1.9 / 2.0 (Q1 2014), puedes usar git merge-base --fork-point para pedir el mejor ancestro común según Git.

Puedes ver esa nueva opción:

  • detallado en " ¿Cómo recupero / vuelvo a sincronizar después de que alguien presiona una rebase o un restablecimiento a una twig publicada? ".
  • utilizado en " ¿Cómo se maneja un repository público que ya ha sido networkingiseñado? ".

Y como commit ad8261d de John Keeping ( johnkeeping ) , git rebase puede usar esa misma nueva --fork-point , que puede ser útil si necesita volver a establecer una base de una twig como customers/acme_patches en devel .
(No digo que esto tenga sentido en su escenario específico)

bueno, git merge-base customers/acme_patches stable debería mostrar el ancestro común de esas dos twigs.

Podría intentar, por ejemplo, gitk --left-right customers/acme_patches...stable (¡tenga en count tres puntos!). Esto mostrará todas las confirmaciones que están en esas twigs y no en la base de fusión. El uso de – --left-right marcará cada confirmación con una flecha hacia la izquierda o hacia la derecha según la twig en la que estén en la flecha izquierda si están en clientes / acme_patches y una flecha hacia la derecha si están estables.

Posiblemente también add --date-order que he encontrado a veces ayuda a dar sentido a la salida.

(Puede usar esta syntax con git log --graph lugar de gitk pero en este caso, la visualización del gráfico visual es una gran mejora).

No estoy seguro si cubre todos los casos, pero aquí están las funciones que surgieron:

 git_branch_contains() { local b=$1 local c=$2 IFS_=$IFS IFS=$'\n' local branches=($(git branch --contains "$c" | sed -E 's/^(\*| ) //')) IFS=$IFS_ for b2 in "${branches[@]:+${branches[@]}}"; do if [ "$b2" = "$b" ]; then return 0 fi done return 1 } git_upstream_branch() { local b=$1 local c1=$(git merge-base --fork-point master "$b") || local c1= local c2=$(git merge-base --fork-point dev "$b") || local c2= if ! [ "$c1" ]; then echo dev return fi if ! [ "$c2" ]; then echo master return fi local fp if git merge-base --is-ancestor "$c1" "$c2"; then fp=$c2 else fp=$c1 fi if git_branch_contains master "$fp" && ! git_branch_contains dev "$fp"; then echo master else echo dev fi } 

Y aquí está el script para probarlos ( git-upstream-branch-test.sh ):

 #!/usr/bin/env bash set -eu . git-upstream-branch.sh git_commit() { if ! [ "${commit_i:-}" ]; then commit_i=0 fi (( commit_i++ )) || true echo "$commit_i" > "$commit_i" git add "$commit_i" git commit -qm "c$commit_i" } git_merge() { if ! [ "${merge_i:-}" ]; then merge_i=0 fi (( merge_i++ )) || true git merge -m "$merge_i" $1 } A_TOPOLOGY=${1:-} mkdir git-upstream-branch-test-repo cd git-upstream-branch-test-repo git init -q if [ "$A_TOPOLOGY" = 10 ]; then git_commit git_commit git checkout -qb dev git_commit git_commit git checkout -q master git_commit git_commit c=$(git rev-parse HEAD) git_commit git_commit git checkout -q dev git checkout -qb t1 git_commit git_commit git checkout -q dev git_commit git_commit git rebase --onto "$c" dev t1 elif [ "$A_TOPOLOGY" = 11 ]; then git_commit git_commit git checkout -qb dev git_commit git_commit git checkout -q master git_commit git_commit git checkout -q dev c=$(git rev-parse HEAD) git_commit git_commit git checkout -q master git checkout -qb t1 git_commit git_commit git checkout -q master git_commit git_commit git rebase --onto "$c" master t1 else git_commit git_commit git checkout -qb dev git_commit git_commit git checkout -q master git_commit git_commit if [ "$A_TOPOLOGY" = 4 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 6 ]; then git_merge dev git_commit git_commit git checkout -q dev git_commit git_commit git checkout -q master elif [ "$A_TOPOLOGY" = 7 ] || [ "$A_TOPOLOGY" = 8 ] || [ "$A_TOPOLOGY" = 9 ]; then git checkout -q dev git_merge master git_commit git_commit git checkout -q master git_commit git_commit fi git checkout -qb t1 git_commit git_commit git checkout -q master git_commit git_commit if [ "$A_TOPOLOGY" = 2 ] || [ "$A_TOPOLOGY" = 5 ] || [ "$A_TOPOLOGY" = 8 ]; then git_merge dev elif [ "$A_TOPOLOGY" = 3 ] || [ "$A_TOPOLOGY" = 6 ] || [ "$A_TOPOLOGY" = 9 ]; then git checkout -q dev git_merge master fi fi git --no-pager log --oneline --graph --decorate --all git_upstream_branch t1 

Úselo así,

 $ rm -rf git-upstream-branch-test-repo && ./git-upstream-branch-test.sh NUMBER 

Donde NUMBER es un número del 1 al 11 para especificar qué caso (topología) probar.