Ho 57 filiali locali. So di aver apportato una modifica a un determinato file in uno di essi, ma non sono sicuro di quale. C'è qualche tipo di comando che posso eseguire per trovare quali rami contengono modifiche a un determinato file?
Risposte:
Trova tutti i rami che contengono una modifica a FILENAME (anche se prima del punto di diramazione (non registrato))
FILENAME="<filename>"
git log --all --format=%H $FILENAME | while read f; do git branch --contains $f; done | sort -u
Ispezionare manualmente:
gitk --all --date-order -- $FILENAME
Trova tutte le modifiche a FILENAME non unite allo schema:
git for-each-ref --format="%(refname:short)" refs/heads | grep -v master | while read br; do git cherry master $br | while read x h; do if [ "`git log -n 1 --format=%H $h -- $FILENAME`" = "$h" ]; then echo $br; fi; done; done | sort -u
git log -Schange …
o git log --grep LOGMESSAGE …
(con ... che rappresenta il resto del comando che ho menzionato).
gitk --all -- filename
che ti mostrerà graficamente tutte le modifiche a quel file. Se riesci a identificare il commit in questione, puoi usarlo git branch --contains
per vedere in quali rami è migrato il commit. Se vuoi vedere su quale ramo è stato originariamente creato il commit in questione , allora google git-what-branch, ma tieni presente che le unioni in avanti veloce possono oscurare tali informazioni.
git log --all --format='--contains %H' "$file" | xargs git branch
Tutto ciò che serve è
git log --all -- path/to/file/filename
Se vuoi conoscere subito la filiale puoi utilizzare anche:
git log --all --format=%5 -- path/to/file/filename | xargs -I{} -n 1 echo {} found in && git branch --contains {}
Inoltre, se hai rinominato, potresti volerlo includere --follow
per il comando Git log.
--source
lì e sei d'oro.
Sembra che questo sia ancora un problema senza una soluzione adeguata. Non ho abbastanza crediti per commentare, quindi ecco il mio piccolo contributo.
La prima soluzione di Seth Robertson ha funzionato per me, ma mi ha dato solo rami locali, tra i quali molti falsi positivi, probabilmente a causa delle fusioni dal ramo stabile.
La seconda soluzione di Adam Dymitruk non ha funzionato affatto per me. Per cominciare, cos'è --format =% 5? Non è riconosciuto da git, non sono riuscito a trovare nulla al riguardo e non sono riuscito a farlo funzionare con altre opzioni di formato.
Ma la sua prima soluzione combinata con l'opzione --source e con un semplice grep si è dimostrata utile:
git log --all --source -- <filename> | grep -o "refs/.*" | sort -u
Questo mi dà un numero di tag e rami remoti e un ramo locale, dove ho apportato le ultime modifiche al file. Non sono sicuro di quanto sia completo.
AGGIORNAMENTO secondo la richiesta di @nealmcb, ordinando i rami in base alla modifica più recente:
Per prima cosa, potresti cambiare grep in "refs / heads /.*", che ti darà solo i branch locali. Se ci sono solo pochi rami, puoi esaminare l'ultimo commit di ognuno in questo modo:
git log -1 <branch> -- <filename>
Se ci sono più rami e vuoi davvero automatizzarli, puoi combinare i due comandi usando xargs, git log formatting e un altro ordinamento in questo one-liner:
git log --all --source -- <filename> | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' -- <filename> | sort -r
Ciò si tradurrà in un output come questo:
2020-05-07T15:10:59+02:00 refs/heads/branch1
2020-05-05T16:11:52+02:00 refs/heads/branch3
2020-03-27T11:45:48+00:00 refs/heads/branch2
So che questa domanda è antica, ma ho continuato a tornarci prima di sviluppare la mia soluzione. Penso che sia più elegante e grazie all'uso della base di unione filtra i rami indesiderati.
#!/bin/bash
file=$1
base=${2:-master}
b=$(tput bold) # Pretty print
n=$(tput sgr0)
echo "Searching for branches with changes to $file related to the $base branch"
# We look through all the local branches using plumbing
for branch in $(git for-each-ref --format='%(refname:short)' refs/heads/); do
# We're establishing a shared ancestor between base and branch, to only find forward changes.
merge_base=$(git merge-base $base $branch)
# Check if there are any changes in a given path.
changes=$(git diff $merge_base..$branch --stat -- $file)
if [[ ! -z $changes ]]; then
echo "Branch: ${b}$branch${n} | Merge Base: $merge_base"
# Show change statistics pretty formatted
git diff $merge_base..$branch --stat -- $file
fi
done
Se lo metti in PATH come git-find-changes
(con autorizzazioni eseguibili), puoi chiamarlo congit find-changes /path
Output di esempio per
git find-changes app/models/
Branch: update_callbacks | Merge base: db07d23b5d9600d88ba0864aca8fe79aad14e55b
app/models/api/callback_config.rb | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
Branch: repackaging | Merge base: 76578b9b7ee373fbe541a9e39cf93cf5ff150c73
app/models/order.rb | 38 ++++++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
Quello che segue è un metodo di forza bruta poco elegante, ma mi aspetto che dovrebbe funzionare. Assicurati di aver prima nascosto tutte le modifiche non salvate poiché cambierà il ramo in cui ti trovi attualmente.
for branch in $(git for-each-ref --format="%(refname:short)" refs/heads); do
git checkout $branch && git grep SOMETHING
done
git log -S
for-each-ref
rispetti ancora quella short
bandiera però. Detto questo, ignora la mia risposta; le altre risposte sono migliori.