检索文件中特定行的提交日志?


502

有没有什么办法让git为您提供涉及文件中特定的提交的提交日志?

类似于git blame,但git blame将向您显示触及特定行的最后提交。

我真的很想得到类似的日志,而不是文件中任何位置的提交列表,而只是触及特定行的提交。


Answers:


631

另请参见Git:发现哪些提交触及了一系列行


从Git 1.8.4开始git log必须-L查看一系列线的演变。

例如,假设您查看git blame的输出。这里的-L 150,+11意思是“只看行150到150 + 11”:

$ git blame -L 150,+11 -- git-web--browse.sh
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 150)            die "The browser $browser is not
a180055a git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:36 +0100 151)    fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 152) fi
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 153) 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 154) case "$browser" in
81f42f11 git-web--browse.sh (Giuseppe Bilotta 2010-12-03 17:47:38 +0100 155) firefox|iceweasel|seamonkey|iceape)
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 156)    # Check version because firefox < 2.0 do
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 157)    vers=$(expr "$($browser_path -version)" 
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 158)    NEWTAB='-new-tab'
5d6491c7 git-browse-help.sh (Christian Couder 2007-12-02 06:07:55 +0100 159)    test "$vers" -lt 2 && NEWTAB=''
a0685a4f git-web--browse.sh (Dmitry Potapov   2008-02-09 23:22:22 -0800 160)    "$browser_path" $NEWTAB "$@" &

您想知道第155行的历史。

然后,使用git log。此处的-L 155,155:git-web--browse.sh意思是“跟踪名为git-web--browse.sh“ 的文件中第155到155行的演变。

$ git log --pretty=short -u -L 155,155:git-web--browse.sh
commit 81f42f11496b9117273939c98d270af273c8a463
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: support opera, seamonkey and elinks

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -143,1 +143,1 @@
-firefox|iceweasel)
+firefox|iceweasel|seamonkey|iceape)

commit a180055a47c6793eaaba6289f623cff32644215b
Author: Giuseppe Bilotta <giuseppe.bilotta@gmail.com>

    web--browse: coding style

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- a/git-web--browse.sh
+++ b/git-web--browse.sh
@@ -142,1 +142,1 @@
-    firefox|iceweasel)
+firefox|iceweasel)

commit 5884f1fe96b33d9666a78e660042b1e3e5f9f4d9
Author: Christian Couder <chriscool@tuxfamily.org>

    Rename 'git-help--browse.sh' to 'git-web--browse.sh'.

diff --git a/git-web--browse.sh b/git-web--browse.sh
--- /dev/null
+++ b/git-web--browse.sh
@@ -0,0 +127,1 @@
+    firefox|iceweasel)

2
'git log --topo-order --graph -u -L 155,155:git-web--browse.sh'-这给出了致命错误:'无效的对象名称155,155'。Git版本:1.8.3.2。有什么建议么?
BairDev

12
升级到Git 1.8.4或更高版本。
马特·麦克卢尔

4
如果我想知道“ commitA中第155行的历史”(而不是HEAD中的第155行)怎么办?我可以简单地使用git log commitA-hash -L 155,155:file-name吗?
伊达

@Flimm,我没有强烈的偏好。
马特·麦克卢尔

这很好用,除非文件已被移动/重命名...似乎--follow不喜欢与行范围args组合。
Mike Ellery 2015年

66

您可以使用镐来获取一组提交。

git log -S'the line from your file' -- path/to/your/file.txt

这将为您提供影响该文件中该文本的所有提交。如果在某个时候重命名了文件,则可以添加--follow-parent。

如果您想检查每个编辑中的提交,则可以将该结果传递给git show:

git log ... | xargs -n 1 git show

5
我不确定是否会有所帮助。如果文本受到影响,则该行不再相同,因此镐只会向您显示最近的更改。然后git log -S'the previous version of the line',您必须做类似的事情,就像最终要使用进行操作一样git blame -L。而且它会比慢git blame,因为它必须在各处查找文本,而不仅仅是在给定的位置。
卡斯卡贝尔2011年

您可以在其中使用正则表达式使其更易于接受。当前,如果没有一些精心设计的脚本,就无法及时“遍历补丁”。我希望gitk将来能在其补丁程序视图中获得此功能。
亚当·迪米特鲁克

3
为什么将此称为镐头?:)
CiprianTomoiagă18年


14

一种非常简单的方法是使用vim-fugitive。只需在vim中打开文件,选择您要使用的行V,然后输入

:Glog

现在,您可以使用:cnext:cprev查看修改该行的文件的所有修订。在任何时候,输入:Gblame以查看sha,作者和日期信息。


13

简化@matt的答案-

git blame -L14,15 -- <file_path>

在这里,你会因为台词而受到指责14 to 15

由于-Loption期望Range作为参数,因此我们无法Blame使用-Loption` 获得一行

参考


10

我不相信有任何内置功能。由于很少有几行更改多次而文件的其余部分也没有实质性更改,因此这很棘手,因此您往往会导致行号更改很多。

如果您很幸运,该行始终具有一些识别特性,例如,对名称从未更改过的变量的赋值,则可以将regex选项用于git blame -L。例如:

git blame -L '/variable_name *= */',+1

但这只会找到该正则表达式的第一个匹配项,因此,如果您没有很好的匹配行的方法,那么它就不会有太大帮助。

我想你可以破解一些东西。我现在没有时间写代码,但是...这些方面的东西。运行git blame -n -L $n,$n $file。第一场是上一次提交感动,第二场是行号提交,因为它可能已经改变。抓住它们,然后运行git blame -n $n,$n $commit^ $file,即从上次更改文件之前的提交开始执行相同的操作。

(请注意,如果最后更改该行的提交是合并提交,将使您失败。如果将行作为合并冲突解决方案的一部分进行更改,则这可能是发生这种情况的主要方式。)

编辑:我从2011年3月开始偶然遇到此邮件列表帖子,其中提到了这一点,tiggit gui具有一项可以帮助您完成此操作的功能。看来git本身已经考虑了该功能,但尚未完成。


6

这将调用git blame每一个有意义的修订秀行$LINE的文件$FILE

git log --format=format:%H $FILE | xargs -L 1 git blame $FILE -L $LINE,$LINE

像往常一样,责备在每行的开头显示修订号。您可以附加

| sort | uniq -c

要获得汇总结果,例如更改此行的提交列表。(不完全是,如果仅移动了代码,则对于行的不同内容,这可能会两次显示相同的提交ID。要进行更详细的分析,您必须git blame对相邻提交的结果进行滞后比较。有人吗? )


再次,我认为这行不通,因为它无法跟踪该行的先前位置。因此,如果在2 commits之前添加一行,您将看到另一行
Vic Seedoubleyew

6

这是定义git别名的解决方案,因此您可以像这样使用它:

git rblame -M -n -L '/REGEX/,+1' FILE

输出示例:

00000000 18 (Not Committed Yet 2013-08-19 13:04:52 +0000 728) fooREGEXbar
15227b97 18 (User1 2013-07-11 18:51:26 +0000 728) fooREGEX
1748695d 23 (User2 2013-03-19 21:09:09 +0000 741) REGEXbar

您可以在.gitconfig中定义别名,也可以只运行以下命令

git config alias.rblame !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); echo $line; done' dumb_param

这是一个丑陋的单行代码,因此这是一个去混淆的等效bash函数:

git-rblame () {
    local commit line
    while line=$(git blame "$@" $commit 2>/dev/null); do
        commit="${line:0:8}^"
        if [ "00000000^" == "$commit" ]; then
            commit=$(git rev-parse HEAD)
        fi
        echo $line
    done
}

镐解决方案(git log --pickaxe-regex -S'REGEX')仅会为您添加行/删除行,而不给包含正则表达式的行其他更改。

此解决方案的局限性在于git blame仅返回第一个REGEX匹配项,因此,如果存在多个匹配项,则递归可能会“跳转”到另一行。确保检查完整的历史记录输出以发现那些“跳跃”,然后修复REGEX以忽略寄生线。

最后,这是一个替代版本,它在每次提交时都运行git show以获得完整的diff:

git config alias.rblameshow !sh -c 'while line=$(git blame "$@" $commit 2>/dev/null); do commit=${line:0:8}^; [ 00000000^ == $commit ] && commit=$(git rev-parse HEAD); git show $commit; done' dumb_param

2

您可以在git blame命令中混合使用git blamegit log命令来检索每个提交的摘要并将其追加。类似于以下bash + awk脚本。它将提交摘要附加为代码注释内联。

git blame FILE_NAME | awk -F" " \
'{
   commit = substr($0, 0, 8);
   if (!a[commit]) {
     query = "git log --oneline -n 1 " commit " --";
     (query | getline a[commit]);
   }
   print $0 "  // " substr(a[commit], 9);
 }'

一行:

git blame FILE_NAME | awk -F" " '{ commit = substr($0, 0, 8); if (!a[commit]) { query = "git log --oneline -n 1 " commit " --"; (query | getline a[commit]); } print $0 "  // " substr(a[commit], 9); }'

2

就我而言,行号随着时间的推移发生了很大变化。我也在git 1.8.3上,它在“ git blame -L”中不支持正则表达式。(RHEL7仍然有1.8.3)

myfile=haproxy.cfg
git rev-list HEAD -- $myfile | while read i
do
    git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"
done | grep "<sometext>"

Oneliner:

myfile=<myfile> ; git rev-list HEAD -- $myfile | while read i; do     git diff -U0 ${i}^ $i $myfile | sed "s/^/$i /"; done | grep "<sometext>"

当然,这可以做成脚本或函数。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.