У мене 57 місцевих відділень. Я знаю, що змінив певний файл в одному з них, але не впевнений, який саме. Чи є якась команда, яку я можу запустити, щоб знайти, які гілки містять зміни до певного файлу?
Відповіді:
Знайти всі гілки, що містять зміну на FILENAME (навіть якщо до (незаписаної) точки гілки)
FILENAME="<filename>"
git log --all --format=%H $FILENAME | while read f; do git branch --contains $f; done | sort -u
Перевірити вручну:
gitk --all --date-order -- $FILENAME
Знайти всі зміни до FILENAME, не об’єднані для обробки:
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 …або git log --grep LOGMESSAGE …(із… що представляє решту команди, про яку я згадав).
gitk --all -- filenameяке графічно покаже всі зміни до цього файлу. Якщо ви можете ідентифікувати спірний коміт, тоді ви можете використовувати, git branch --containsщоб побачити, до яких гілок коміт мігрував. Якщо ви хочете побачити, на якій гілці спочатку був створений відповідний коміт, тоді google git-what-branch, але майте на увазі, що швидкі злиття можуть закрити цю інформацію.
git log --all --format='--contains %H' "$file" | xargs git branch
Все, що тобі потрібно, це
git log --all -- path/to/file/filename
Якщо ви хочете дізнатися гілку відразу, ви також можете використовувати:
git log --all --format=%5 -- path/to/file/filename | xargs -I{} -n 1 echo {} found in && git branch --contains {}
Крім того, якщо у вас були якісь перейменування, ви можете включити --followдля команди журналу Git.
--sourceтуди, і ви золоті.
Схоже, це все ще проблема без відповідного рішення. У мене недостатньо кредитів, щоб коментувати, тож ось мій невеликий внесок.
Перше рішення Сета Робертсона начебто спрацювало для мене, але дало мені лише місцеві гілки, серед яких багато помилкових спрацьовувань, ймовірно через злиття зі стабільної гілки.
Друге рішення Адама Димітрука для мене взагалі не працювало. Для початку, що таке --format =% 5? Це не розпізнано git, я не міг нічого про це знайти і не міг змусити його працювати з іншими параметрами формату.
Але його перше рішення у поєднанні з варіантом --source та простим grep виявилось корисним:
git log --all --source -- <filename> | grep -o "refs/.*" | sort -u
Це дає мені ряд віддалених тегів та гілок та одну локальну гілку, де я вніс останні зміни у файл. Не впевнений, наскільки це повно.
ОНОВИТИ відповідно до запиту @nealmcb, сортуючи гілки за останньою зміною:
По-перше, ви можете змінити grep на "refs / heads /.*", що надасть вам лише місцеві відділення. Якщо є лише кілька гілок, ви можете вивчити останні коміти кожного з них так:
git log -1 <branch> -- <filename>
Якщо гілок є більше, і ви дійсно хочете це автоматизувати, ви можете поєднати дві команди за допомогою xargs, форматування журналу git та іншого сортування в цей однорядковий рядок:
git log --all --source -- <filename> | grep -o "refs/heads/.*" | sort -u | xargs -I '{}' git log -1 --format=%aI%x20%S '{}' -- <filename> | sort -r
Це призведе до такого виводу:
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
Я знаю, що це питання давнє, але я повертався до нього, перш ніж розробляти власне рішення. Я вважаю, що це більш елегантно, і завдяки використанню основи злиття відфільтровує небажані гілки.
#!/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
Якщо ви помістите його в PATH як git-find-changes(з дозволами на виконання) - тоді ви можете зателефонувати йому за допомогоюgit find-changes /path
Приклад виводу для
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(+)
Далі наводиться неелегантний метод грубої сили, але я сподіваюся, він повинен спрацювати. Переконайтеся, що спочатку ви заховали будь-які незмінені зміни, оскільки вони змінять, на якій гілці ви зараз перебуваєте.
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все ще поважає цей shortпрапор. Тим не менш, ігноруйте мою відповідь; інші відповіді кращі.