Immagina la seguente storia:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Come posso trovare quando il commit "c" è stato unito al master (ovvero, trova il comando di unione "h")?
Immagina la seguente storia:
c---e---g--- feature
/ \
-a---b---d---f---h--- master
Come posso trovare quando il commit "c" è stato unito al master (ovvero, trova il comando di unione "h")?
Risposte:
Il tuo esempio mostra che il ramo feature
è ancora disponibile.
In tal caso h
è l'ultimo risultato di:
git log master ^feature --ancestry-path
Se il ramo feature
non è più disponibile, è possibile mostrare i commit di unione nella riga della cronologia tra c
e master
:
git log <SHA-1_for_c>..master --ancestry-path --merges
Questo mostrerà comunque anche tutte le fusioni avvenute dopo h
, e tra e
e g
avanti feature
.
Confronto del risultato dei seguenti comandi:
git rev-list <SHA-1_for_c>..master --ancestry-path
git rev-list <SHA-1_for_c>..master --first-parent
ti darà lo SHA-1 di h
come l'ultima riga in comune.
Se lo hai disponibile, puoi utilizzare comm -1 -2
questi risultati. Se sei su msysgit, puoi usare il seguente codice perl per confrontare:
perl -ne 'print if ($seen{$_} .= @ARGV) =~ /10$/' file1 file2
(codice perl da http://www.cyberciti.biz/faq/command-to-display-lines-common-in-files/ , che lo ha preso da "qualcuno del gruppo di notizie comp.unix.shell").
Vedere la sostituzione del processo se si desidera trasformarlo in una riga.
master
stato unito feature
, quindi immediatamente feature
unito master
come avanzamento rapido (punta di feature
rimpiazzo master
). Ciò causerebbe la --first-parent
restituzione del genitore sbagliato?
comm -1 -2
ma non ha funzionato. comm
Funziona solo su linee ordinate. (Il perl one-liner funziona, anche se non riuscivo a leggerlo.)
git find-merge h master
(non restituisce nulla ma deve restituire h), git find-merge d master
(restituisce f ma deve restituire d), git find-merge c feature
(restituisce e ma deve restituire g).
Aggiungi questo al tuo ~/.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'"
Quindi puoi usare gli alias in questo modo:
# current branch
git find-merge <SHA-1>
# specify master
git find-merge <SHA-1> master
Per visualizzare il messaggio del commit unione e altri dettagli, utilizzare git show-merge
con gli stessi argomenti.
(Basato sulla risposta di Gauthier . Grazie a Rosen Matev e javabrett per aver risolto un problema con sort
.)
sort -k2 | uniq -f1 -d | sort -n | tail -1 | cut -f2
non trovare correttamente l'ultima riga in comune. Ecco un esempio in cui fallisce.
16db9fef5c581ab0c56137d04ef08ef1bf82b0b7
qui quando lo eseguo sul tuo incolla, non è previsto? Su quale sistema operativo sei?
29c40c3a3b33196d4e79793bd8e503a03753bad1
git-get-merge localizzerà e mostrerà il commit di merge che stai cercando:
pip install git-get-merge
git get-merge <SHA-1>
Il comando segue i figli del commit dato fino a quando non viene trovata un'unione in un altro ramo (presumibilmente master).
Cioè, per riassumere il post di 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: poiché utilizza la sostituzione di processo " <()
", non è compatibile con POSIX e potrebbe non funzionare con la shell. Funziona con bash
o zsh
comunque.
<()
non è compatibile con POSIX. È necessario utilizzare bash
, zsh
o un rivestimento portante sostituzione di processo . Ho modificato la mia risposta di conseguenza.
Avevo bisogno di farlo, e in qualche modo ho trovato git-when-merged
(che in realtà fa riferimento a questa domanda SO, ma Michael Haggerty non ha mai aggiunto un riferimento al suo bellissimo script Python qui). Quindi ora ho.
Basandoci sulla grande risposta di Gauthier, non abbiamo bisogno di usare comm
per confrontare le liste. Dal momento che stiamo cercando l'ultimo risultato in --ancestry-path
cui è presente anche --first-parent
, possiamo semplicemente cercare quest'ultimo nell'output del primo:
git rev-list <SHA>..master --ancestry-path | grep -f <(git rev-list <SHA>..master --first-parent) | tail -1
O per qualcosa di scattante e riutilizzabile, ecco una funzione in cui entrare .bashrc
:
function git-find-merge() {
git rev-list $1..master --ancestry-path | grep -f <(git rev-list $1..master --first-parent) | tail -1
}
comm
non ha funzionato quando gli input non sono stati ordinati.
Uso sotto lo script bash che metto sul percorso ~/bin/git-find-merge
. Si basa sulla risposta di Gauthier e sulla risposta di Evilstreak con alcune modifiche per gestire casi d'angolo. comm
genera quando gli input non sono ordinati. grep -f
funziona perfettamente.
Valigie angolari:
~/bin/git-find-merge
script:
#!/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
Il che mi permette di fare questo:
(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
Questo script è disponibile anche sul mio github .
La mia versione ruby dell'idea di @ robinst funziona due volte più velocemente (il che è importante quando si cerca un commit molto vecchio).
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
Puoi semplicemente usarlo in questo modo:
ruby find-commit.rb SHA master
Puoi provare qualcosa del genere. L'idea è di iterare attraverso tutti i commit di unione e vedere se il commit "c" è raggiungibile da uno di essi:
$ 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
Ho dovuto farlo più volte (grazie a tutti coloro che hanno risposto a questa domanda!) E ho finito per scrivere una sceneggiatura (usando il metodo di Gauthier) che ho potuto aggiungere alla mia piccola raccolta di programmi di utilità git. Puoi trovarlo qui: https://github.com/mwoehlke/git-utils/blob/master/bin/git-merge-point .