Git log解释

5

我正在构建一个Git日志查看器,最近在查看git log的输出时,有三个问题让我产生了疑问。由于Git SCM书籍和类似的资源中没有关于确切输出的文档,所以我不得不在Stack Overflow上询问:

  1. index 1234567..1234567 123456是什么?它与提交的sha不匹配吗?
  2. 更改行后逗号后面的int是什么意思? @@ -40,20 +40,20 @@
  3. 更改行第二个@@之后的部分是什么意思?

例如,来自Git SCM Book “查看提交历史记录”

$ git log -p -2
commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number

diff --git a/Rakefile b/Rakefile
index a874b73..8f94139 100644
--- a/Rakefile
+++ b/Rakefile
@@ -5,5 +5,5 @@ require 'rake/gempackagetask'
 spec = Gem::Specification.new do |s|
     s.name      =   "simplegit"
-    s.version   =   "0.1.0"
+    s.version   =   "0.1.1"
     s.author    =   "Scott Chacon"
     s.email     =   "schacon@gee-mail.com
3个回答

6

1. "1234567..1234567 123456"是什么意思?它与提交的sha不匹配?

git-log man page中可以看到:

索引行包括更改前后的SHA-1校验和。如果文件模式未更改,则包括< mode >; 否则,单独的行指示旧模式和新模式。

好的,很酷...但这是什么意思呢?

所以,git通过内部存储地址来存储对象。这些SHA-1校验和是您更改之前和之后文件版本的地址。

您可以使用git内部命令访问这些文件来查看:

$git cat-file -p a874b73
<--- the contents of the file before the commit --->

$git cat-file -p 8f94139
<--- the contents of the file after the commit --->

第二个数字,即<mode>,表示Unix文件权限。请参阅this answer for more info about how to read them以获取更多信息。
请参见下面的示例,解释哈希值!
编辑:糟糕,忘记回答第二和第三个问题了。

2. 更改行后逗号后面的int是什么?@@ -40,20 +40,20 @@?

更改使用统一差异格式显示。该维基百科文章有一个相当好的解释,但基本上该行是范围信息。它由两对组成:第一对有一个-符号,第二对有一个+符号。 -对引用原始文件,+对引用第二个文件。 在每个对中,第一个数字是要显示的块的起始行号,第二个数字是将要显示的行数。

所以@@ -10,5 +10,10 @@

意味着您添加了5行,因此第二个版本中的块比原来多了五行。

3. 更改行后面的部分是什么?

这一行应该是块所在的上下文。因此,正如@TimWolla下面的答案指出的那样,如果这是一个C/C++程序,那么可能是该块所在函数的名称。在这种情况下,require 'rake/gempackagetask'是Ruby代码,可能是程序的第一行,因此diff认为这是适当的名称来引用此部分。


这里有几个展示git的SHA-1校验和工作的例子:
$ touch newfileA newfileB
$ git add newfile*
$ git commit -m 'added new files'
[master a49cb1c] added new files
 2 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 newfileA
 create mode 100644 newfileB

$ git log -p -1
commit a49cb1c5292082a6ed9c7f09e1bce2636e60ab93
Author: Nathan Daly <NHDaly@gmail.com>
Date:   Sat Mar 1 16:10:49 2014 -0500

    added new files

diff --git a/newfileA b/newfileA
new file mode 100644
index 0000000..e69de29
diff --git a/newfileB b/newfileB
new file mode 100644
index 0000000..e69de29

你可以看到,在提交之前,这些文件是不存在的(因为没有地址引用先前的版本:因此索引为0000000),在提交后它们被创建了,这些文件的blob地址为e69de29。它们具有相同的哈希值,因为这些文件是相同的,所以没有理由拥有空文件的不同副本。
你可以通过对一个空文件进行哈希来验证这一点。我们得到与之前相同的哈希值(这次是完整长度)。
$ touch blankfile
$ git hash-object blankfile
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

现在,如果我们更改文件的内容:
$ echo 'contents1' > newfileA
$ echo 'contents2' > newfileB
$ git add newfile*
$ git commit -m 'updated newfile contents'    
[master 76827d7] updated newfile contents
 2 files changed, 2 insertions(+)

$ git log -p -1
commit 76827d7af1846c6c0f07ac2b78771cbc34cd6056
Author: Nathan Daly <NHDaly@gmail.com>
Date:   Sat Mar 1 16:18:40 2014 -0500

    updated newfile contents

diff --git a/newfileA b/newfileA
index e69de29..a024003 100644
--- a/newfileA
+++ b/newfileA
@@ -0,0 +1 @@
+contents1
diff --git a/newfileB b/newfileB
index e69de29..6b46faa 100644
--- a/newfileB
+++ b/newfileB
@@ -0,0 +1 @@
+contents2

你可以看到它们现在有不同的哈希值。它们中的每一个都从e69de29对象开始,移动到具有不同地址的新对象。为了验证这一点,我们可以从它们各自的哈希值获取这些对象的内容:
$ git cat-file -p a024003
contents1
$ git cat-file -p 6b46faa
contents2

最后,如果我们再次使它们的内容相等,它们将再次共享哈希值。(再次强调,Git这样做只是为了节省磁盘空间,因为这两个文件除了名称外完全相同)
$ echo 'contents2' > newfileA
$ git add newfileA
$ git commit -m 'now files match'
$ git log -p -1
commit 3f63bcef9290fae616521ec1b380639c6026c5c5
Author: Nathan Daly <NHDaly@gmail.com>
Date:   Sat Mar 1 16:22:29 2014 -0500

    now files match

diff --git a/newfileA b/newfileA
index a024003..6b46faa 100644
--- a/newfileA
+++ b/newfileA
@@ -1 +1 @@
-contents1
+contents2

正如您所见,现在newfileA也有与newfileB相同的哈希值6b46faa

Git中的每个对象都以这样的哈希地址存储,因此在您的git日志查看器应用程序中,您可以使用这些索引哈希来向用户显示每个版本文件的内容!


非常感谢。我花了很长时间才编写测试输出,以真正理解你所解释的一切。可惜我不能多点赞一次 :) - kaiser
没问题,很高兴能帮忙!是啊,在第一次理解哈希之前,我也进行了很多测试输出! - NHDaly

3
为了回答NHDaly的回答未解决的问题:
“@@ -40,20 +40,20 @@”中逗号后面的int是什么意思?
这是跟随的块的长度(没有+-的行数,第一个块有-的行数和第二个块有+的行数),在这种情况下:显示的行数为20
第二个@@后面的部分是什么意思? diff使用一种算法来确定上下文,它最适用于C代码,在那里它应该显示方法头,例如Linux内核的Commit af87d2fe95

糟糕,好眼力。感谢@TimWolla,我已经更新了我的回答并参考了你的! :) - NHDaly
1
+1并感谢您的回答。对于PHP来说,方法头并不是很有效。您可能会得到if、循环或require语句。对于大多数CSS规则也是如此。 - kaiser

0

除了其他(优秀)答案的补充,这里有一些更深入的例子,关于添加/删除行作为统一的差异格式暗示没有逗号值为1(行添加/删除)。这意味着没有逗号值并不意味着null,而是1和零/0并不意味着null,而是1。这可能会让像我这样的一些程序员感到困惑。

例子

以下例子意味着您正在调用git show --unified=0 $sha并且不显示未更改的行。否则,如TimWolla在评论中指出的那样,未更改的行将被包括在内(谢谢)。

@@ -10,5 +10,10 @@

这意味着有5行被删除,10行被添加。

@@ -10,0 +10,2 @@

没有删除任何行,但是添加了2行。

@@ -10 +10,2 @@

删除了一行,添加了两行。

@@ -10 +10 @@

删除了一行,添加了1行。

@@ -10,7 +10 @@

删除了7行代码,添加了1行。

@@ -10,7 +10,0 @@

删除了7行代码,没有添加任何新的代码。


这并不完全正确,因为逗号后面的数字也包括未更改的行。 - TimWolla
@TimWolla编辑了答案。我使用了--unified=0来排除未更改的行。忘记提到这一点了。 - kaiser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接