Mam 57 lokalnych oddziałów. Wiem, że dokonałem zmiany w pewnym pliku w jednym z nich, ale nie jestem pewien, który. Czy jest jakieś polecenie, które mogę uruchomić, aby znaleźć gałęzie zawierające zmiany w określonym pliku?
Odpowiedzi:
Znajdź wszystkie gałęzie, które zawierają zmianę w FILENAME (nawet jeśli przed (nie zarejestrowanym) punktem rozgałęzienia)
FILENAME="<filename>"
git log --all --format=%H $FILENAME | while read f; do git branch --contains $f; done | sort -u
Sprawdź ręcznie:
gitk --all --date-order -- $FILENAME
Znajdź wszystkie zmiany w FILENAME, które nie zostały scalone z wzorcem:
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 …lub git log --grep LOGMESSAGE …(z… reprezentującym resztę polecenia, o którym wspomniałem).
gitk --all -- filenamektóre pokaże graficznie wszystkie zmiany w tym pliku. Jeśli możesz zidentyfikować dane zatwierdzenie, możesz użyć, git branch --containsaby zobaczyć, do jakich gałęzi zostało przeniesione zatwierdzenie. Jeśli chcesz zobaczyć, w której gałęzi zostało pierwotnie utworzone dane zatwierdzenie , skorzystaj z Google git-what-branch, ale pamiętaj, że szybkie scalanie może zasłonić te informacje.
git log --all --format='--contains %H' "$file" | xargs git branch
Wszystko czego potrzebujesz to
git log --all -- path/to/file/filename
Jeśli chcesz od razu poznać oddział, możesz również skorzystać z:
git log --all --format=%5 -- path/to/file/filename | xargs -I{} -n 1 echo {} found in && git branch --contains {}
Ponadto, jeśli masz jakieś zmiany nazw, możesz chcieć dołączyć je --followdo polecenia dziennika Git.
--sourcetam i jesteś złoty.
Wygląda na to, że jest to nadal problem bez odpowiedniego rozwiązania. Nie mam wystarczającej liczby kredytów do skomentowania, więc oto mój mały wkład.
Pierwsze rozwiązanie Setha Robertsona trochę zadziałało, ale dało mi tylko lokalne oddziały, wśród których było wiele fałszywych alarmów, prawdopodobnie z powodu fuzji ze stabilnej gałęzi.
Drugie rozwiązanie Adama Dymitruka w ogóle mi się nie udało. Na początek, co to jest --format =% 5? Nie jest rozpoznawany przez git, nie mogłem nic znaleźć na ten temat i nie mogłem go zmusić do pracy z innymi opcjami formatu.
Ale jego pierwsze rozwiązanie w połączeniu z opcją --source i prostym grepem okazało się pomocne:
git log --all --source -- <filename> | grep -o "refs/.*" | sort -u
To daje mi kilka zdalnych tagów i gałęzi oraz jeden oddział lokalny, w którym wprowadziłem najnowsze zmiany w pliku. Nie wiem, jak kompletne jest to.
AKTUALIZUJ zgodnie z żądaniem @nealmcb, sortowanie gałęzi według ostatniej zmiany:
Najpierw możesz zmienić grep na „refs / heads /.*”, co da ci tylko lokalne gałęzie. Jeśli jest tylko kilka gałęzi, możesz sprawdzić najnowsze zatwierdzenie każdej z nich w następujący sposób:
git log -1 <branch> -- <filename>
Jeśli jest więcej gałęzi i naprawdę chcesz to zautomatyzować, możesz połączyć te dwa polecenia za pomocą xargs, formatowania dziennika git i innego sortowania w jedną linijkę:
git log --all --source -- <filename> | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' -- <filename> | sort -r
Spowoduje to następujący wynik:
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
Wiem, że to pytanie jest starożytne, ale wracałem do niego, zanim opracowałem własne rozwiązanie. Uważam, że jest bardziej elegancki i dzięki zastosowaniu bazy scalającej odfiltrowuje niechciane gałęzie.
#!/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
Jeśli umieścisz go w PATH as git-find-changes(z uprawnieniami do plików wykonywalnych) - możesz to wywołać za pomocągit find-changes /path
Przykładowe dane wyjściowe dla
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(+)
Poniżej znajduje się nieelegancka metoda brutalnej siły, ale spodziewam się, że powinna działać. Upewnij się, że najpierw zachowałeś wszelkie niezatwierdzone zmiany, ponieważ zmieni to gałąź, w której aktualnie jesteś.
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-refnadal przestrzega tej shortflagi. To powiedziawszy, zignoruj moją odpowiedź; inne odpowiedzi są lepsze.