查找包含对给定文件的更改的 Git 分支

我在当地有57家分支机构。我知道我修改了其中一个文件中的某个文件,但我不确定是哪个。是否可以运行某种命令来查找哪些分支包含对某个文件的更改?

39121 次浏览

查找包含对 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

查找没有合并到 master 中的所有对 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

下面是一个不优雅的蛮力方法,但是我希望它能够工作。首先确保您已经隐藏了任何未提交的更改,因为它将切换您当前所在的分支。

for branch in $(git for-each-ref --format="%(refname:short)" refs/heads); do
git checkout $branch && git grep SOMETHING
done

你只需要

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 {}

此外,如果您有任何重命名,您可能希望为 Git log 命令包含 --follow

看来没有合适的解决办法,这个问题还是没有解决。我没有足够的学分来评论,所以这是我的小贡献。

Seth Robertson 的第一个解决方案对我有点用,但只给了我本地分支,其中有很多误报,可能是因为从稳定分支合并的缘故。

亚当 · 迪米特鲁克的第二个解决方案对我一点用都没有。首先,什么是—— format =% 5?它不能被 git 识别,我找不到任何关于它的东西,也无法让它与其他格式选项一起工作。

但是他的第一个解决方案结合了—— source 选项和一个简单的 grep 被证明是有用的:

git log --all --source -- <filename> | grep -o "refs/.*" | sort -u

这给了我一些远程标记和分支以及一个本地分支,在这里我对文件进行了最新的更改。不知道这有多完整。

根据@nealmcb 的请求更新 ,按照最近的更改对分支进行排序:

First, you could change the grep to "refs/heads/.*", which will give you the local branches only. If there are only a few branches, you could examine the latest commit of each one like this:

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

I know this question is ancient, but I kept comming back to it before developing my own solution. I feel it's more elegant and thanks to use of merge base filters out unwanted branches.

#!/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(+)