有没有办法让git给你一个提交日志,只提交触及文件中的特定行?

就像git blame,但git blame会显示触及特定行的LAST commit。

我希望得到一个类似的日志,不是文件中任何地方的提交列表,而是触及特定行的提交。


当前回答

这将调用git blame为每一个有意义的修订显示line $ line文件$ file:

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

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

| sort | uniq -c

要获得聚合结果,可以使用更改这一行的提交列表之类的东西。(不完全是,如果代码只是被移动了,这可能会对行中不同的内容显示相同的提交ID两次。为了进行更详细的分析,您必须对相邻提交的git blame结果进行滞后比较。有人知道吗?)

其他回答

我不相信有什么内置的。这很棘手,因为很少有一行更改多次,而文件的其余部分也没有发生重大更改,所以最终往往会导致行号更改很多。

如果你足够幸运,这一行总是有一些识别特征,例如赋值给一个名称从未改变的变量,你可以使用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月的邮件列表,其中提到tig和git gui有一个功能可以帮助你做到这一点。对于git本身来说,这个特性似乎已经考虑过了,但还没有完成。

你可以通过使用picko -axe来获得一组提交。

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

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

如果你想在每次编辑时检查提交,你可以将结果管道到git show:

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

如果该行的位置(行号)在文件的历史记录中保持不变,这将在每次提交时显示该行的内容:

git log --follow --pretty=format:"%h" -- 'path/to/file' | while read -r hash; do echo $hash && git show $hash:'path/to/file' | head -n 544 | tail -n1; done

将“544”修改为行号,将“/to/file”修改为文件路径。

这将调用git blame为每一个有意义的修订显示line $ line文件$ file:

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

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

| sort | uniq -c

要获得聚合结果,可以使用更改这一行的提交列表之类的东西。(不完全是,如果代码只是被移动了,这可能会对行中不同的内容显示相同的提交ID两次。为了进行更详细的分析,您必须对相邻提交的git blame结果进行滞后比较。有人知道吗?)

请参见Git:发现哪些提交曾经接触过一系列行。


从Git 1.8.4开始,Git log有-L来查看行范围的演变。

例如,假设您查看git blame的输出。这里- l150,+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)