查看提交历史 git log
如果想要查看git的提交历史,可以使用git log
命令。本文会介绍一些常用的命令选项,比如-<n>
、-p
、--stat
、--pretty
等。
默认的git log
命令会显示所有提交历史:
$ git log
commit ccf42476e007db608813193659a5b4a0d3241df3
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:31:54 2017 +0800
change .gitignore
commit da2b5d3db249617ec4b79eb843681600ed141cc9
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:07:36 2017 +0800
add a.txt to .gitignore
commit eb691cca8f9a227d321924ffd094bcfae03d5314
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:05:52 2017 +0800
rename README.txt -> README.md
commit 7c14f66174395dfc30ced57840ad5e9f108c9a0c
Author: wm <1626364188g@gmail.com>
Date: Thu Dec 28 23:47:35 2017 +0800
delete b.txt
# 省略
每个提交的格式都相似,单词commit
(提交)后面跟的一大串(实际是40个)字符,就是这个提交的名字,是一个SHA-1序列,独一无二。接下来显示作者以及提交日期,最后显示提交的描述。
如果只想查看最近的几次提交记录,可以使用-(n)
选项,比如-2
选项只会显示最近的两次提交:
$ git log -2
commit ccf42476e007db608813193659a5b4a0d3241df3
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:31:54 2017 +0800
change .gitignore
commit da2b5d3db249617ec4b79eb843681600ed141cc9
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:07:36 2017 +0800
add a.txt to .gitignore
使用-p
选项可以查看每次的更改:
$ git log -p -1
commit ccf42476e007db608813193659a5b4a0d3241df3
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:31:54 2017 +0800
change .gitignore
diff --git a/.gitignore b/.gitignore
index eaa5fa8..e69de29 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +0,0 @@
-a.txt
使用-stat
选项可以查看每次的简略统计信息:
$ git log --stat -1
commit ccf42476e007db608813193659a5b4a0d3241df3
Author: wm <1626364188g@gmail.com>
Date: Fri Dec 29 11:31:54 2017 +0800
change .gitignore
.gitignore | 1 -
1 file changed, 1 deletion(-)
使用--pretty
选项可以让信息以友好的方式显示,比如--pretty=oneline
会让每条提交信息在一行显示,此外还有short
、full
和fuller
可以用:
$ git log -3 --pretty=oneline
ccf42476e007db608813193659a5b4a0d3241df3 change .gitignore
da2b5d3db249617ec4b79eb843681600ed141cc9 add a.txt to .gitignore
eb691cca8f9a227d321924ffd094bcfae03d5314 rename README.txt -> README.md
--pretty=format
可以自定义输出的内容:
$ git log -3 --pretty=format:"%h - %an, %ar : %s"
ccf4247 - wm, 30 hours ago : change .gitignore
da2b5d3 - wm, 31 hours ago : add a.txt to .gitignore
eb691cc - wm, 31 hours ago : rename README.txt -> README.md
上面的例子中哈希值名字是以简短的开头的几个字母来表示的。
--pretty=format
常用的选项如下:
选项 | 说明 |
---|---|
%H | 提交对象(commit)的完整哈希字串 |
%h | 提交对象的简短哈希字串 |
%T | 树对象(tree)的完整哈希字串 |
%t | 树对象的简短哈希字串 |
%P | 父对象(parent)的完整哈希字串 |
%p | 父对象的简短哈希字串 |
%an | 作者(author)的名字 |
%ae | 作者的电子邮件地址 |
%ad | 作者修订日期(可以用 --date= 选项定制格式) |
%ar | 作者修订日期,按多久以前的方式显示 |
%cn | 提交者(committer)的名字 |
%ce | 提交者的电子邮件地址 |
%cd | 提交日期 |
%cr | 提交日期,按多久以前的方式显示 |
%s | 提交说明 |
git log
的常用选项如下:
选项 | 说明 |
---|---|
-p | 按补丁格式显示每个更新之间的差异 |
--stat | 显示每次更新的文件修改统计信息 |
--shortstat | 只显示 --stat 中最后的行数修改添加移除统计 |
--name-only | 仅在提交信息后显示已修改的文件清单 |
--name-status | 显示新增、修改、删除的文件清单 |
--abbrev-commit | 仅显示 SHA-1 的前几个字符,而非所有的 40 个字符 |
--relative-date | 使用较短的相对时间显示(比如,“2 weeks ago”) |
--graph | 显示 ASCII 图形表示的分支合并历史 |
--pretty | 使用其他格式显示历史提交信息。可用的选项包括 oneline,short,full,fuller 和 format(后跟指定格式) |
除此之外,git log
还有很多输出限制选项,比如--since
和--until
就很常用,其中选项--since
会显示某个时间点之后的提交历史,而--until
会显示某个时间点之前的历史,下面是一个例子:
$ git log --since=2.days --pretty=format:'%h %cr : %s'
ccf4247 33 hours ago : change .gitignore
da2b5d3 34 hours ago : add a.txt to .gitignore
eb691cc 34 hours ago : rename README.txt -> README.md
7c14f66 2 days ago : delete b.txt
389faae 2 days ago : add b.txt
a2e55d5 2 days ago : delete a.txt
381fe8e 2 days ago : add a.txt
136fc21 2 days ago : git is covenient
上面的例子以--pretty=format
指定的格式显示出了两天以内的提交历史。
git log
常用的输出限制选项:
选项 | 说明 |
---|---|
-(n) | 仅显示最近的 n 条提交 |
--since, --after | 仅显示指定时间之后的提交 |
--until, --before | 仅显示指定时间之前的提交 |
--author | 仅显示指定作者相关的提交 |
--committer | 仅显示指定提交者相关的提交 |
--grep | 仅显示含指定关键字的提交 |
-S | 仅显示添加或移除了某个关键字的提交 |
取出 git checkout -- FILE
有的时候难免会写了一些错误的内容,如果想要将工作目录中的文件从暂存区或者git仓库恢复出来,需要使用git checkout
命令。git checkout
命令,顾名思义,取出的意思。这个命令可以将一个分支的内容取出来放到工作目录,也可将本分支暂存区或者git仓库中的内容取出来放到工作目录,因此它可以用来切换分支,也可以用来恢复文件,这里只讲第二个,也就是恢复文件的用法。
现在让我们在README.md
中胡乱的加一句:
$ echo "asdfgh" >> README.md
$ cat README.md
Hi, Git!
Git is a free and open source distributed version control system.
Git is very easy to learn.
Git is very fast and convenient.
asdfgh
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
显然,现在git提示我们README.md
文件有修改,但是我们发现文件只是多了一句毫无意义的话,现在我们想要恢复修改之前的版本,那么就需要使用git checkout -- FILE
命令(当然可以直接删除最后一句话,这只是一个人为制造的例子):
$ git checkout -- README.md
$ cat README.md
Hi, Git!
Git is a free and open source distributed version control system.
Git is very easy to learn.
Git is very fast and convenient.
$ git status
On branch master
nothing to commit, working directory clean
上面的例子中,在checkout
后,README.md
文件恢复成了在修改之前(上次提交时)的样子,并且工作目录是干净的。
git checkout -- FILE
命令按下面的逻辑运行:
- 如果该文件已经保存到暂存区,那么恢复到暂存区文件的状态。
- 如果该文件还没有保存到暂存区,那么恢复到上次提交时的状态。
请在执行此命令时务必写上命令中的--
。
git reset的三个用法与git reflog
git reset
,重置。常见的有三个用法,分别是--mixed
、--soft
和--hard
。
-
--mixed
:默认命令选项,即不写命令选项时执行此命令选项。仅仅重置暂存区(index)至给定提交,不重置工作目录。 -
--soft
:暂存区与工作目录都不会被重置,仅仅把HEAD指向给定提交。执行后效果是自给定提交以来所有的改变都是未提交的。 -
--hard
:重置暂存区和工作目录,并且将HEAD指向给定提交。这个命令很危险,因为它会丢失自给定提交以后所有的更改。
下面我们更改README.md
,并且将其提交到暂存区:
$ echo "asdfgh" >> README.md
$ git add README.md
$ git status -s
M README.md
我们现在README.md
被添加了一行无用的内容,并且添加到了暂存区,为了重置暂存区,需要git reset HEAD README.md
命令,效果是仅仅将暂存区的README.md
重置至HEAD(即最近提交),不会重置工作目录:
$ git reset HEAD README.md
Unstaged changes after reset:
M README.md
$ git status -s
M README.md
$ cat README.md | tail -1
asdfgh
可见,暂存区被重置了,而工作目录并没有被重置。
假设我们没有发现这个问题,这个问题被提交了,有没有补救的方法呢?
$ git commit -a -m "add a wrong line asdfgh to README.md"
$ git status -s
$ cat README.md | tail -2
Git is very fast and convenient.
asdfgh
$ git log --pretty=oneline -3
af490893aba74d956c57583078ec0df343a06aae add a wrong line asdfgh to README.md
ccf42476e007db608813193659a5b4a0d3241df3 change .gitignore
da2b5d3db249617ec4b79eb843681600ed141cc9 add a.txt to .gitignore
糟糕,现在已经被提交了,怎么办?这就要用到--hard
了,它就将工作目录、暂存区重置,并且将HEAD指向给定提交:
$ git reset --hard HEAD^
HEAD is now at ccf4247 change .gitignore
$ cat README.md | tail -2
Git is very easy to learn.
Git is very fast and convenient.
$ git status -s
$ git log --pretty=oneline -2
ccf42476e007db608813193659a5b4a0d3241df3 change .gitignore
da2b5d3db249617ec4b79eb843681600ed141cc9 add a.txt to .gitignore
HEAD在重置前指向最新的提交,HEAD^
表示最新提交的前一次提交,HEAD^^
表示最新提交的前一次提交的前一次提交……为了简便,HEAD~99
表示表示最新提交的前99次提交。
所以上例中的git reset --hard HEAD^
将工作目录和暂存区全部重置到前一次提交,并且将HEAD指向前一次提交,后面的命令结果显示确实是这样。
git reset --hard ccf4247
可以达到同样的效果,它使用给定提交的哈希字符串代替HEAD^
,不用把哈希字符串写全,但是最少要保证唯一性,我建议最少写7位。
可见,git reset --hard
会将给定提交之后的所有修改丢弃,所以请谨慎使用。
但是现在我们发现最后那句无厘头的话好像还挺有意思,能不能再找回来呢?(你不觉得有意思是正常的,但是书总得往下写)
我们发现git log
里的记录已经没有了,怎么办呢?
git reflog
记录了所有的索引变化,所以使用该命令可以查到索引变化的日志,便可以从中找到给定提交的哈希字符串了!
$ git reflog
ccf4247 HEAD@{2}: reset: moving to HEAD^
af49089 HEAD@{3}: commit: add a wrong line asdfgh to README.md
从上面看到,添加那行无厘头句子的哈希字符串是af49089...
,所以使用git reset --hard af49089
就可以啦!
$ git reset --hard af49089
HEAD is now at af49089 add a wrong line asdfgh to README.md
$ cat README.md | tail -2
Git is very fast and convenient.
asdfgh
$ git log --pretty=oneline -2
af490893aba74d956c57583078ec0df343a06aae add a wrong line asdfgh to README.md
ccf42476e007db608813193659a5b4a0d3241df3 change .gitignore
$ git status -s
$
现在都找回来啦哈哈!
最后,来说说--soft
选项,它不会重置工作目录与暂存区,只会将HEAD指向给定提交。效果是自给定提交以来所有修改都是未提交状态。
现在我们将再向README.md
中添加两句话,并且分别提交:
$ echo "qwerty" >> README.md
$ git commit -a -m "add qwerty to README.md"
[master 721f8ff] add qwerty to README.md
1 file changed, 1 insertion(+)
$ echo "zxcvbn" >> README.md
$ git commit -a -m "add zxcvbn to README.md"
[master 64e53ee] add zxcvbn to README.md
1 file changed, 1 insertion(+)
$ git status -s
$
$ git log --pretty=oneline -3
64e53eeb47738ffd81ff7770758b774f60080b46 add zxcvbn to README.md
721f8ffb54bd93e7d75aed6ff9bf93e2f9eb8ca1 add qwerty to README.md
af490893aba74d956c57583078ec0df343a06aae add a wrong line asdfgh to README.md
好的,现在我们确定这两个提交都是正确无误的,希望它们能“合并”成一个提交,怎么办?
git reset --soft
将帮助我们解决这个问题,它不会修改工作目录和暂存区,只修改HEAD的指向。
$ git reset --soft af49089
$ git status -s
M README.md
$ cat README.md | tail -2
qwerty
zxcvbn
上面的例子中,新添加的两行都成了未提交的内容。现在提交就可将他们合并成一个提交:
$ git commit -a -m "add two wrong line to README.md"
[master 14bd627] add two wrong line to README.md
1 file changed, 2 insertions(+)
$ git log --pretty=oneline -2
14bd6272cde43128877f191364361a7194ba6e6c add two wrong line to README.md
af490893aba74d956c57583078ec0df343a06aae add a wrong line asdfgh to README.md