Imaginez l'histoire suivante:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Comment puis-je trouver quand le commit "c" a été fusionné dans master (c'est-à-dire, trouver le commit de fusion "h")?
Imaginez l'histoire suivante:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Comment puis-je trouver quand le commit "c" a été fusionné dans master (c'est-à-dire, trouver le commit de fusion "h")?
Réponses:
Votre exemple montre que la branche feature
est toujours disponible.
Dans ce cas, h
le dernier résultat de:
git log master ^feature --ancestry-path
Si la branche feature
n'est plus disponible, vous pouvez afficher les validations de fusion dans la ligne d'historique entre c
et master
:
git log <SHA-1_for_c>..master --ancestry-path --merges
Cela montrera cependant également toutes les fusions qui se sont produites après h
, et entre e
et g
sur feature
.
Comparaison du résultat des commandes suivantes:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
vous donnera le SHA-1 de h
comme dernière ligne en commun.
Si vous l'avez disponible, vous pouvez l'utiliser comm -1 -2
sur ces résultats. Si vous êtes sur msysgit, vous pouvez utiliser le code Perl suivant pour comparer:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(code perl de http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , qui l'a emprunté à "quelqu'un du groupe de nouvelles comp.unix.shell").
Voir la substitution de processus si vous voulez en faire un one-liner.
master
été fusionné dans feature
, puis feature
est immédiatement fusionné en master
tant qu'avance rapide (pointe des feature
remplacements master
). Cela provoquerait-il --first-parent
le retour du mauvais parent?
comm -1 -2
mais ça n'a pas marché. comm
ne fonctionne que sur des lignes triées. (Le perl one-liner fonctionne, bien que je ne puisse pas le lire.)
git find-merge h master
(ne renvoie rien mais doit renvoyer h), git find-merge d master
(renvoie f mais doit renvoyer d), git find-merge c feature
(renvoie e mais doit retourner g).
Ajoutez ceci à votre ~/.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'"
Ensuite, vous pouvez utiliser les alias comme ceci:
# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
Pour voir le message de la validation de fusion et d'autres détails, utilisez git show-merge
avec les mêmes arguments.
(Basé sur la réponse de Gauthier . Merci à Rosen Matev et javabrett d' avoir corrigé un problème avec sort
.)
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
ne pas trouver correctement la dernière ligne en commun. Voici un exemple d 'échec.
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
ici lorsque je l'exécute sur votre pâte, n'est-ce pas prévu? Sur quel OS êtes-vous?
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-merge localisera et affichera le commit de fusion que vous recherchez:
pip install git-get-merge
git get-merge <SHA-1>
La commande suit les enfants du commit donné jusqu'à ce qu'une fusion dans une autre branche (probablement maître) soit trouvée.
Autrement dit, pour résumer le post 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
EDIT: parce que cela utilise la substitution de processus " <()
", il n'est pas compatible POSIX, et il peut ne pas fonctionner avec votre shell. Cela fonctionne avec bash
ou zsh
bien.
<()
n'est pas compatible POSIX. Vous devez utiliser bash
, zsh
ou un shell prenant en charge la substitution de processus . J'ai modifié ma réponse en conséquence.
J'avais besoin de le faire et j'ai trouvé git-when-merged
(qui fait référence à cette question SO, mais Michael Haggerty n'a jamais ajouté de référence à son très beau script Python ici). Alors maintenant je l'ai.
En nous appuyant sur la bonne réponse de Gauthier, nous n'avons pas besoin d'utiliser comm
pour comparer les listes. Puisque nous recherchons le dernier résultat dans --ancestry-path
lequel est également in --first-parent
, nous pouvons simplement grep pour ce dernier dans la sortie du premier:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
Ou pour quelque chose de vif et réutilisable, voici une fonction dans laquelle entrer .bashrc
:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
comm
ne fonctionnait pas lorsque les entrées n'étaient pas triées.
J'utilise ci-dessous le script bash que je place au chemin ~/bin/git-find-merge
. Il est basé sur la réponse de Gauthier et la réponse de evilstreak avec quelques modifications pour traiter les cas d'angle. comm
jette lorsque les entrées ne sont pas triées. grep -f
fonctionne parfaitement.
Cas d'angle:
~/bin/git-find-merge
scénario:
#!/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
Ce qui me permet de faire ceci:
(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
Ce script est également disponible sur mon github .
Ma version ruby de l'idée de @ robinst fonctionne deux fois plus vite (ce qui est important lors de la recherche de très vieux commit).
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
Vous pouvez simplement l'utiliser comme ceci:
ruby find-commit.rb SHA master
Vous pouvez essayer quelque chose comme ça. L'idée est de parcourir tous les commit de fusion et de voir si le commit "c" est accessible à partir de l'un d'eux:
$ 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
J'ai dû le faire plusieurs fois (merci à tous ceux qui ont répondu à cette question!), Et j'ai fini par écrire un script (en utilisant la méthode de Gauthier) que je pourrais ajouter à ma petite collection d'utilitaires git. Vous pouvez le trouver ici: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point .