Imagine la siguiente historia:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
¿Cómo puedo encontrar cuando commit "c" se ha fusionado en master (es decir, find merge commit "h")?
Imagine la siguiente historia:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
¿Cómo puedo encontrar cuando commit "c" se ha fusionado en master (es decir, find merge commit "h")?
Respuestas:
Su ejemplo muestra que la rama featureaún está disponible.
En ese caso hes el último resultado de:
git log master ^feature --ancestry-path
Si la rama featureya no está disponible, puede mostrar las confirmaciones de fusión en la línea del historial entre cy master:
git log <SHA-1_for_c>..master --ancestry-path --merges
Esto sin embargo, también le mostrará todas las fusiones que sucedieron después h, y entre ey gsobre feature.
Comparando el resultado de los siguientes comandos:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
le dará el SHA-1 hcomo la última fila en común.
Si lo tiene disponible, puede usarlo comm -1 -2en estos resultados. Si está en msysgit, puede usar el siguiente código perl para comparar:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(código perl de http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , que lo tomó de "alguien en el grupo de noticias comp.unix.shell").
Vea la sustitución del proceso si desea que sea una línea.
masterse fusionó featuree inmediatamente featurese fusionó mastercomo un avance rápido (la punta de los featurereemplazos master). ¿Causaría eso --first-parentdevolver al padre equivocado?
comm -1 -2pero no funcionó. commsolo funciona en líneas ordenadas. (El perl one-liner funciona, aunque no pude leerlo)
git find-merge h master(no devuelve nada pero debería devolver h), git find-merge d master(devuelve f pero debería devolver d), git find-merge c feature(devuelve e pero debería devolver g).
Agregue esto a su ~/.gitconfig:
[alias]
find-merge = "!sh -c 'commit=$0 && branch=${1:-HEAD} && (git rev-list $commit..$branch --ancestry-path | cat -n; git rev-list $commit..$branch --first-parent | cat -n) | sort -k2 -s | uniq -f1 -d | sort -n | tail -1 | cut -f2'"
show-merge = "!sh -c 'merge=$(git find-merge $0 $1) && [ -n \"$merge\" ] && git show $merge'"
Entonces puedes usar los alias de esta manera:
# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
Para ver el mensaje de confirmación de fusión y otros detalles, úselo git show-mergecon los mismos argumentos.
(Basado en la respuesta de Gauthier . Gracias a Rosen Matev y javabrett por corregir un problema con sort).
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2no está encontrando correctamente la última fila en común. Aquí hay un ejemplo donde falla.
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7aquí cuando lo ejecuto en su pasta, ¿no es eso lo que se espera? ¿En qué sistema operativo estás?
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-merge localizará y mostrará la confirmación de fusión que está buscando:
pip install git-get-merge
git get-merge <SHA-1>
El comando sigue a los hijos del commit dado hasta que se encuentre una fusión en otra rama (presumiblemente master).
Es decir, para resumir la publicación de Gauthier:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' <(git rev-list --ancestry-path <SHA-1_for_c>..master) <(git rev-list --first-parent <SHA-1_for_c>..master) | tail -n 1
EDITAR: debido a que utiliza la sustitución de proceso " <()", no es compatible con POSIX y es posible que no funcione con su shell. Funciona con basho zshsin embargo.
<()no es compatible con POSIX. Necesita usar bash, zsho una sustitución de proceso de soporte de shell . Edité mi respuesta en consecuencia.
Necesitaba hacer esto, y de alguna manera lo encontré git-when-merged(que en realidad hace referencia a esta pregunta SO, pero Michael Haggerty nunca agregó una referencia a su muy lindo script Python aquí). Entonces ahora tengo.
Sobre la base de la gran respuesta de Gauthier, no necesitamos usar commpara comparar las listas. Como estamos buscando el último resultado en el --ancestry-pathque también está --first-parent, simplemente podemos buscar el último en la salida del primero:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
O para algo ágil y reutilizable, aquí hay una función para resaltar .bashrc:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
commno funcionaba cuando las entradas no estaban ordenadas.
Para la multitud de Ruby, hay git-wherede . Muy fácil.
$ gem install git-whence
$ git whence 1234567
234557 Merge pull request #203 from branch/pathway
Yo uso el script bash que coloco en el camino ~/bin/git-find-merge. Se basa en la respuesta de Gauthier y la respuesta de evilstreak con algunos retoques para manejar casos de esquina. commse lanza cuando las entradas no están ordenadas. grep -ffunciona perfectamente.
Casos de esquina:
~/bin/git-find-merge guión:
#!/bin/bash
commit=$1
if [ -z $commit ]; then
echo 1>&2 "fatal: commit is required"
exit 1
fi
commit=$(git rev-parse $commit)
branch=${2-@}
# if branch points to commit (both are same), then return commit
if [ $commit == $(git rev-parse $branch) ]; then
git log -1 $commit
exit
fi
# if commit is a merge commit on first-parent path of branch,
# then return commit
# if commit is a NON-merge commit on first-parent path of branch,
# then return branch as it's either a ff merge or commit is only on branch
# and there is not a good way to figure out the right commit
if [[ $(git log --first-parent --pretty='%P' $commit..$branch | \
cut -d' ' -f1 | \
grep $commit | wc -l) -eq 1 ]]; then
if [ $(git show -s --format="%P" $commit | wc -w) -gt 1 ]; then
# if commit is a merge commit
git log -1 $commit
else
# if commit is a NON-merge commit
echo 1>&2 ""
echo 1>&2 "error: returning the branch commit (ff merge or commit only on branch)"
echo 1>&2 ""
git log -1 $branch
fi
exit
fi
# 1st common commit from bottom of first-parent and ancestry-path
merge=$(grep -f \
<(git rev-list --first-parent $commit..$branch) \
<(git rev-list --ancestry-path $commit..$branch) \
| tail -1)
if [ ! -z $merge ]; then
git log -1 $merge
exit
fi
# merge commit not found
echo 1>&2 "fatal: no merge commit found"
exit 1
Lo que me permite hacer esto:
(master)
$ git find-merge <commit> # to find when commit merged to current branch
$ git find-merge <branch> # to find when branch merged to current branch
$ git find-merge <commit> pu # to find when commit merged to pu branch
Este script también está disponible en mi github .
Mi versión rubí de la idea de @ robinst funciona dos veces más rápido (lo cual es importante cuando busco un commit muy antiguo).
find-commit.rb
commit = ARGV[0]
master = ARGV[1] || 'origin/master'
unless commit
puts "Usage: find-commit.rb commit [master-branch]"
puts "Will show commit that merged <commit> into <master-branch>"
exit 1
end
parents = `git rev-list #{commit}..#{master} --reverse --first-parent --merges`.split("\n")
ancestry = `git rev-list #{commit}..#{master} --reverse --ancestry-path --merges`.split("\n")
merge = (parents & ancestry)[0]
if merge
system "git show #{merge}"
else
puts "#{master} doesn't include #{commit}"
exit 2
end
Puedes usarlo así:
ruby find-commit.rb SHA master
Puedes probar algo como esto. La idea es iterar a través de todas las confirmaciones de fusión y ver si la confirmación "c" es accesible desde una de ellas:
$ git log --merges --format='%h' master | while read mergecommit; do
if git log --format='%h' $mergecommit|grep -q $c; then
echo $mergecommit;
break
fi
done
git rev-list <SHA-1_for_c>..master --ancestry-path --merges
Tuve que hacer esto varias veces (¡gracias a todos los que respondieron esta pregunta!), Y terminé escribiendo un script (usando el método de Gauthier) que podría agregar a mi pequeña colección de utilidades git. Puede encontrarlo aquí: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point .