У меня 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 log.
--sourceтуда, и вы золотой.
Похоже, это проблема без соответствующего решения. У меня недостаточно кредитов для комментариев, так что вот мой небольшой вклад.
1-е решение Сета Робертсона вроде сработало для меня, но дало мне только локальные ветки, среди которых было много ложных срабатываний, вероятно, из-за слияний из стабильной ветки.
Второе решение Адама Димитрука у меня вообще не сработало. Для начала, что --format =% 5? Он не распознается git, я ничего не мог найти об этом и не мог заставить его работать с другими параметрами формата.
Но его 1-е решение в сочетании с параметром --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флаг. Тем не менее, игнорируйте мой ответ; другие ответы лучше.