log

git log 显示一个分支中提交的更改记录

到目前为止,我们已经提交快照到项目中,在不同的各自分离的上下文中切换, 但假如我们忘了自己是如何到目前这一步的那该怎么办?或者假如我们想知道此分支与彼分支到底有啥区别? Git 提供了一个告诉你使你达成当前快照的所有提交消息的工具,叫做 git log

要理解日志(log)命令,你需要了解当执行 git commit 以存储一个快照的时候,都有啥信息被保存了。 除了文件详单、提交消息和提交者的信息,Git 还保存了你的此次提交所基于的快照。 也就是,假如你克隆了一个项目,你是在什么快照的基础上做的修改而得到新保存的快照的? 这有益于为项目进程提供上下文,使 Git 能够弄明白谁做了什么改动。 如果 Git 有你的快照所基于的快照的话,它就能自动判断你都改变了什么。而新提交所基于的提交,被称作新提交的“父亲”。

某分支的按时间排序的“父亲”列表,当你在该分支时,可以执行 git log 以查看。 例如,如果我们在本章中操作的 Hello World 项目中执行 git log,我们可以看到已提交的消息。

$ git log
commit 8d585ea6faf99facd39b55d6f6a3b3f481ad0d3d
Merge: 3cbb6aa 3ac015d
Author: Scott Chacon 
Date:   Fri Jun 4 12:59:47 2010 +0200

    Merge branch "fix_readme"

    Conflicts:
        README

commit 3cbb6aae5c0cbd711c098e113ae436801371c95e
Author: Scott Chacon 
Date:   Fri Jun 4 12:58:53 2010 +0200

    fixed readme title differently

commit 3ac015da8ade34d4c7ebeffa2053fcac33fb495b
Author: Scott Chacon 
Date:   Fri Jun 4 12:58:36 2010 +0200

    fixed readme title

commit 558151a95567ba4181bab5746bc8f34bd87143d6
Merge: b7ae93b 3467b0a
Author: Scott Chacon 
Date:   Fri Jun 4 12:37:05 2010 +0200

    Merge branch "change_class"
...

我们可以用 --oneline 选项来查看历史记录的紧凑简洁的版本。

$ git log --oneline
8d585ea Merge branch "fix_readme"
3cbb6aa fixed readme title differently
3ac015d fixed readme title
558151a Merge branch "change_class"
b7ae93b added from ruby
3467b0a changed the class name
17f4acf first commit

这告诉我们的是,此项目的开发历史。如果提交消息描述性很好,这就能为我们提供关于有啥改动被应用、或者影响了当前快照的状态、以及这快照里头都有啥。

我们还可以用它的十分有帮助的 --graph 选项,查看历史中什么时候出现了分支、合并。以下为相同的命令,开启了拓扑图选项:

$ git log --oneline --graph
*   8d585ea Merge branch "fix_readme"
|
| * 3ac015d fixed readme title
* | 3cbb6aa fixed readme title differently
|/
*   558151a Merge branch "change_class"
|
| * 3467b0a changed the class name
* | b7ae93b added from ruby
|/
* 17f4acf first commit

现在我们可以更清楚明了地看到何时工作分叉、又何时归并。 这对查看发生了什么、应用了什么改变很有帮助,并且极大地帮助你管理你的分支。 让我们创建一个分支,在里头做些事情,然后切回到主分支,也做点事情,然后看看 log 命令是如何帮助我们理清这俩分支上都发生了啥的。

首先我们创建一个分支,来添加 Erlang 编程语言的 Hello World 示例 —— 我们想要在一个分支里头做这个,以避免让可能还不能工作的代码弄乱我们的稳定分支。 这样就可以切来切去,片叶不沾身。

$ git checkout -b erlang
Switched to a new branch "erlang"
$ vim erlang_hw.erl
$ git add erlang_hw.erl
$ git commit -m "added erlang"
[erlang ab5ab4c] added erlang
 1 files changed, 5 insertions(+), 0 deletions(-)
 create mode 100644 erlang_hw.erl

由于我们玩函数式编程很开心,以至于沉迷其中,又在“erlang”分支中添加了一个 Haskell 的示例程序。

$ vim haskell.hs
$ git add haskell.hs
$ git commit -m "added haskell"
[erlang 1834130] added haskell
 1 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 haskell.hs

最后,我们决定还是把 Ruby 程序的类名改回原先的样子。与其创建另一个分支,我们可以返回主分支,改变它,然后直接提交。

$ git checkout master
Switched to branch "master"
$ ls
README  ruby.rb
$ vim ruby.rb
$ git commit -am "reverted to old class name"
[master 594f90b] reverted to old class name
 1 files changed, 2 insertions(+), 2 deletions(-)

现在假设我们有段时间不做这个项目了,我们做别的去了。 当我们回来的时候,我们想知道“erlang”分支都是啥,而主分支的进度又是怎样。 仅仅看分支的名字,我们是无从知道自己还在里面有 Haskell 的改动的,但是用 git log 我们就可以。 如果你在命令行中提供一个分支名字,它就会显示该分支历史中“可及”的提交,即从该分支创立起可追溯的影响了最终的快照的提交。

$ git log --oneline erlang
1834130 added haskell
ab5ab4c added erlang
8d585ea Merge branch "fix_readme"
3cbb6aa fixed readme title differently
3ac015d fixed readme title
558151a Merge branch "change_class"
b7ae93b added from ruby
3467b0a changed the class name
17f4acf first commit

如此,我们很容易就看到分支里头还包括了 Haskell 代码(高亮显示了)。 更酷的是,我们很容易地告诉 Git,我们只对某个分支中可及的提交感兴趣。换句话说,某分支中与其他分支相比唯一的提交。

在此例中,如果我们想要合并“erlang”分支,我们需要看当合并的时候,都有啥提交会作用到我们的快照上去。 我们告诉 Git 的方式是,在不想要看到的分支前放一个 ^。 例如,如果我们想要看“erlang”分支中但不在主分支中的提交,我们可以用 erlang ^master,或者反之。

$ git log --oneline erlang ^master
1834130 added haskell
ab5ab4c added erlang
$ git log --oneline master ^erlang
594f90b reverted to old class name

这为我们提供了一个良好的、简易的分支管理工具。它使我们能够非常容易地查看对某个分支唯一的提交,从而知道我们缺少什么,以及当我们要合并时,会有什么被合并进去。

简而言之 使用 git log 列出促成当前分支目前的快照的提交历史记录。这使你能够看到项目是如何到达现在的状况的。

文章导航