C'è un modo per scoprire da quale ramo proviene un commit dato il suo valore hash SHA-1 ?
Punti bonus se puoi dirmi come farlo usando Ruby Grit.
C'è un modo per scoprire da quale ramo proviene un commit dato il suo valore hash SHA-1 ?
Punti bonus se puoi dirmi come farlo usando Ruby Grit.
Risposte:
Mentre Dav ha ragione a dire che le informazioni non sono memorizzate direttamente, ciò non significa che non puoi mai scoprirlo. Ecco alcune cose che puoi fare.
git branch -a --contains <commit>
Questo ti dirà tutti i rami che hanno il proprio impegno nella loro storia. Ovviamente questo è meno utile se il commit è già stato unito.
Se si lavora nel repository in cui è stato eseguito il commit, è possibile cercare i reflog per la riga per quel commit. I reflog più vecchi di 90 giorni sono potati da git-gc, quindi se il commit è troppo vecchio, non lo troverai. Detto questo, puoi farlo:
git reflog show --all | grep a871742
per trovare commit a871742. Nota che DEVI utilizzare le prime 7 cifre abbreviate del commit. L'output dovrebbe essere qualcosa del genere:
a871742 refs/heads/completion@{0}: commit (amend): mpc-completion: total rewrite
indicando che il commit è stato eseguito sul ramo "completamento". L'output predefinito mostra hash di commit abbreviati, quindi assicurati di non cercare l'hash completo o non troverai nulla.
git reflog show
è in realtà solo un alias per git log -g --abbrev-commit --pretty=oneline
, quindi se vuoi giocherellare con il formato di output per rendere disponibili diverse cose per grep, questo è il tuo punto di partenza!
Se non stai lavorando nel repository in cui è stato eseguito il commit, il meglio che puoi fare in questo caso è esaminare i reflog e trovare quando il commit è stato introdotto per la prima volta nel tuo repository; con un po 'di fortuna, hai recuperato il ramo in cui era impegnato. Questo è un po 'più complesso, perché non è possibile eseguire contemporaneamente il commit dell'albero e il reflog. Si vorrebbe analizzare l'output reflog, esaminando ogni hash per vedere se contiene il commit desiderato o meno.
Questo dipende dal flusso di lavoro, ma con buoni flussi di lavoro, i commit vengono effettuati sui rami di sviluppo che vengono poi uniti. È possibile effettuare ciò:
git log --merges <commit>..
per vedere i commit di unione che hanno il commit dato come antenato. (Se il commit è stato unito solo una volta, il primo dovrebbe essere l'unione che stai cercando; altrimenti dovresti esaminarne alcuni, suppongo.) Il messaggio di commit di unione dovrebbe contenere il nome del ramo che è stato unito.
Se si desidera poter contare su ciò, è possibile utilizzare l' --no-ff
opzione git merge
per forzare la creazione del commit di unione anche nel caso di avanzamento rapido. (Non essere troppo ansioso, però. Ciò potrebbe diventare offuscato se abusato .) La risposta di VonC a una domanda correlata elabora utili su questo argomento.
git describe
sufficiente, perché i tag (annotati) possono essere visualizzati come più significativi dei rami.
--no-ff
opzione per assicurarti che sia sempre presente un commit di unione, in modo da poter sempre tracciare il percorso di un determinato commit man mano che viene unito al master.
-a
bandiera al primo comando, ad es.git branch -a --contains <commit>
-r
.
merge --no-ff
per registrare in modo affidabile il nome del ramo quando si unisce. Altrimenti, pensa ai nomi delle filiali come etichette brevi temporanee e impegna le descrizioni come permanenti. "A quale breve nome ci siamo riferiti a questo durante lo sviluppo?" non dovrebbe essere una domanda tanto importante quanto "cosa fa questo commit?"
Questo semplice comando funziona come un incantesimo:
git name-rev <SHA>
Ad esempio (dove test-branch è il nome del ramo):
git name-rev 651ad3a
251ad3a remotes/origin/test-branch
Anche questo funziona per scenari complessi, come:
origin/branchA/
/branchB
/commit<SHA1>
/commit<SHA2>
Qui git name-rev commit<SHA2>
restituisce branchB .
git name-rev --name-only <SHA>
più utile per ottenere solo il nome del ramo. La mia domanda ... Può restituire più di un ramo in qualsiasi circostanza?
Aggiornamento dicembre 2013:
git-what-branch
(Perl script, vedi sotto) non sembra più essere mantenuto.git-when-merged
è un'alternativa scritta in Python che funziona molto bene per me.
Si basa su " Trova commit unione che include un commit specifico ".
git when-merged [OPTIONS] COMMIT [BRANCH...]
Trova quando un commit è stato unito in uno o più rami.
Trova il commit di merge che ha portatoCOMMIT
ai BRANCH specificati.In particolare, cerca il commit più vecchio nella cronologia del primo genitore
BRANCH
che contiene l'COMMIT
antenato.
Risposta originale settembre 2010:
Sebastien Douche ha appena twittato (16 minuti prima di questa risposta SO):
git-what-branch : Scopri su quale ramo si trova un commit o come è arrivato a un ramo con nome
Questo è uno script Perl di Seth Robertson che sembra molto interessante:
SINOSSI
git-what-branch [--allref] [--all] [--topo-order | --date-order ]
[--quiet] [--reference-branch=branchname] [--reference=reference]
<commit-hash/tag>...
PANORAMICA
Indica (per impostazione predefinita) il primo percorso causale dei commit e delle fusioni per far sì che il commit richiesto sia entrato in un ramo denominato. Se un commit è stato effettuato direttamente su un ramo con nome, quello ovviamente è il primo percorso.
Per primo percorso causale, intendiamo il percorso che si è unito il più presto in un ramo denominato, per tempo di commit (a meno che non
--topo-order
sia specificato).PRESTAZIONE
Se molti rami (ad es. Centinaia) contengono il commit, il sistema potrebbe impiegare molto tempo (per un commit specifico nella struttura di Linux, ci sono voluti 8 secondi per esplorare un ramo, ma c'erano oltre 200 rami candidati) per rintracciare il percorso a ciascun commit.
La selezione di un particolare--reference-branch --reference tag
da esaminare sarà centinaia di volte più veloce (se hai centinaia di rami candidati).ESEMPI
# git-what-branch --all 1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4
1f9c381fa3e0b9b9042e310c69df87eaf9b46ea4 first merged onto master using the following minimal temporal path:
v2.6.12-rc3-450-g1f9c381 merged up at v2.6.12-rc3-590-gbfd4bda (Thu May 5 08:59:37 2005)
v2.6.12-rc3-590-gbfd4bda merged up at v2.6.12-rc3-461-g84e48b6 (Tue May 3 18:27:24 2005)
v2.6.12-rc3-461-g84e48b6 is on master
v2.6.12-rc3-461-g84e48b6 is on v2.6.12-n
[...]
Questo programma non tiene conto degli effetti della raccolta delle ciliegie sul commit degli interessi, ma solo unisce le operazioni.
git-what-branch
non sembra più essere mantenuto. git-when-merged è un'alternativa scritta in Python che funziona molto bene per me.
Ad esempio, per trovare quel c0118fa
commit proviene da redesign_interactions
:
* ccfd449 (HEAD -> develop) Require to return undef if no digits found
* 93dd5ff Merge pull request #4 from KES777/clean_api
|\
| * 39d82d1 Fix tc0118faests for debugging debugger internals
| * ed67179 Move &push_frame out of core
| * 2fd84b5 Do not lose info about call point
| * 3ab09a2 Improve debugger output: Show info about emitted events
| * a435005 Merge branch 'redesign_interactions' into clean_api
| |\
| | * a06cc29 Code comments
| | * d5d6266 Remove copy/paste code
| | * c0118fa Allow command to choose how continue interaction
| | * 19cb534 Emit &interact event
Dovresti eseguire:
git log c0118fa..HEAD --ancestry-path --merges
E scorrere verso il basso per trovare l'ultimo commit di unione . Che è:
commit a435005445a6752dfe788b8d994e155b3cd9778f
Merge: 0953cac a06cc29
Author: Eugen Konkov
Date: Sat Oct 1 00:54:18 2016 +0300
Merge branch 'redesign_interactions' into clean_api
Aggiornare
O solo un comando:
git log c0118fa..HEAD --ancestry-path --merges --oneline --color | tail -n 1
git merge -m"Any String Here"
, oscurerà le informazioni sul ramo di origine e di destinazione.
Merge: f6b70fa d58bdcb
. Puoi nominare il tuo commit di unione come te. Non avrò importanza
git branch --contains <ref>
è il comando "porcellana" più ovvio per farlo. Se vuoi fare qualcosa di simile solo con i comandi "idraulici":
COMMIT=$(git rev-parse <ref>) # expands hash if needed
for BRANCH in $(git for-each-ref --format "%(refname)" refs/heads); do
if $(git rev-list $BRANCH | fgrep -q $COMMIT); then
echo $BRANCH
fi
done
(crosspost da questa risposta SO )
khichar.anil ha coperto gran parte di questo nella sua risposta.
Sto solo aggiungendo la bandiera che rimuoverà i tag dall'elenco dei nomi delle revisioni. Questo ci dà:
git name-rev --name-only --exclude=tags/* $SHA
L'opzione di un uomo povero è usare lo strumento tig
1 su HEAD
, cercare il commit e quindi seguire visivamente la linea da quel commit di backup fino a quando non viene visualizzato un commit di unione. Il messaggio di unione predefinito dovrebbe specificare quale ramo viene unito a dove :)
1 Tig è un'interfaccia in modalità testo basata su ncurses per Git. Funziona principalmente come un browser di repository Git, ma può anche aiutare a mettere in scena le modifiche per il commit a livello di blocco e fungere da cercapersone per l'output da vari comandi Git.
Come esperimento, ho creato un hook post-commit che memorizza le informazioni sul ramo attualmente estratto nei metadati di commit. Ho anche leggermente modificato gitk per mostrare quelle informazioni.
Puoi verificarlo qui: https://github.com/pajp/branch-info-commits
Ho a che fare con lo stesso problema ( pipeline multibranch Jenkins ): avere solo informazioni di commit e cercare di trovare un nome di filiale da cui proviene originariamente questo commit. Deve funzionare per filiali remote, le copie locali non sono disponibili.
Questo è ciò con cui lavoro:
git rev-parse HEAD | xargs git name-rev
Opzionalmente è possibile eliminare l'output:
git rev-parse HEAD | xargs git name-rev | cut -d' ' -f2 | sed 's/remotes\/origin\///g'
Penso che qualcuno dovrebbe affrontare lo stesso problema che non è in grado di scoprire il ramo, anche se in realtà esiste in un ramo.
Faresti meglio a tirare tutto per primo:
git pull --all
Quindi cerca la filiale:
git name-rev <SHA>
o:
git branch --contains <SHA>
Se l'OP sta cercando di determinare la storia che è stato attraversato da un ramo in cui una particolare commit è stato creato ( "scoprire cosa ramo un commit viene da dato il suo valore di hash SHA-1"), quindi senza la reflog Non ci sono alcun record nel database degli oggetti Git che mostra quale ramo denominato era associato a quale cronologia di commit.
(L'ho pubblicato come risposta in risposta a un commento.)
Spero che questa sceneggiatura illustri il mio punto:
rm -rf /tmp/r1 /tmp/r2; mkdir /tmp/r1; cd /tmp/r1
git init; git config user.name n; git config user.email e@x.io
git commit -m"empty" --allow-empty; git branch -m b1; git branch b2
git checkout b1; touch f1; git add f1; git commit -m"Add f1"
git checkout b2; touch f2; git add f2; git commit -m"Add f2"
git merge -m"merge branches" b1; git checkout b1; git merge b2
git clone /tmp/r1 /tmp/r2; cd /tmp/r2; git fetch origin b2:b2
set -x;
cd /tmp/r1; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
cd /tmp/r2; git log --oneline --graph --decorate; git reflog b1; git reflog b2;
L'output mostra la mancanza di alcun modo per sapere se il commit con 'Aggiungi f1' proviene dal ramo b1 o b2 dal clone remoto / tmp / r2.
(Le ultime righe dell'output qui)
+ cd /tmp/r1
+ git log --oneline --graph --decorate
* f0c707d (HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: merge b2: Fast-forward
086c9ce b1@{1}: commit: Add f1
18feb84 b1@{2}: Branch: renamed refs/heads/master to refs/heads/b1
18feb84 b1@{3}: commit (initial): empty
+ git reflog b2
f0c707d b2@{0}: merge b1: Merge made by the 'recursive' strategy.
80c10e5 b2@{1}: commit: Add f2
18feb84 b2@{2}: branch: Created from b1
+ cd /tmp/r2
+ git log --oneline --graph --decorate
* f0c707d (HEAD, origin/b2, origin/b1, origin/HEAD, b2, b1) merge branches
|\
| * 086c9ce Add f1
* | 80c10e5 Add f2
|/
* 18feb84 empty
+ git reflog b1
f0c707d b1@{0}: clone: from /tmp/r1
+ git reflog b2
f0c707d b2@{0}: fetch origin b2:b2: storing head
git log 80c10e5..HEAD --ancestry-path --merges --oneline --color | tail -n 1
e i git log 086c9ce..HEAD --ancestry-path --merges --oneline --color | tail -n 1
comandi per entrambi i casi?
$ git log HEAD^1..HEAD --ancestry-path --merges --oneline --color | tail -n 1
quali sono i rendimenti 376142d merge branches
e $ git log HEAD^2..HEAD --ancestry-path --merges --oneline --color | tail -n 1
quali i rendimenti 376142d merge branches
- che mostra il riepilogo del commit unione, che (come stavo affermando) può essere sovrascritto quando viene creata l'unione, probabilmente offuscando la cronologia del ramo dell'unione.
Usa quanto segue se ti interessa lo stato di uscita della shell:
branch-current
- il nome della filiale attualebranch-names
- nomi di rami puliti (uno per riga)branch-name
- Accertarsi che venga restituito solo un ramo branch-names
Entrambi branch-name
e branch-names
accettano un commit come argomento, e HEAD
se non ne viene fornito uno di default .
branch-current = "symbolic-ref --short HEAD" # https://stackoverflow.com/a/19585361/5353461
branch-names = !"[ -z \"$1\" ] && git branch-current 2>/dev/null || git branch --format='%(refname:short)' --contains \"${1:-HEAD}\" #" # https://stackoverflow.com/a/19585361/5353461
branch-name = !"br=$(git branch-names \"$1\") && case \"$br\" in *$'\\n'*) printf \"Multiple branches:\\n%s\" \"$br\">&2; exit 1;; esac; echo \"$br\" #"
% git branch-name eae13ea
master
% echo $?
0
0
.% git branch-name 4bc6188
Multiple branches:
attempt-extract
master%
% echo $?
1
1
.A causa dello stato di uscita, questi possono essere costruiti in modo sicuro. Ad esempio, per ottenere il telecomando utilizzato per il recupero:
remote-fetch = !"branch=$(git branch-name \"$1\") && git config branch.\"$branch\".remote || echo origin #"
Per trovare la filiale locale:
grep -lR YOUR_COMMIT .git/refs/heads | sed 's/.git\/refs\/heads\///g'
Per trovare il ramo remoto:
grep -lR $commit .git/refs/remotes | sed 's/.git\/refs\/remotes\///g'
Oltre a cercare in tutto l'albero fino a trovare un hash corrispondente, no.