git版本控制

查看提交历史 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会让每条提交信息在一行显示,此外还有shortfullfuller可以用:

$ 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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,189评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,577评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,857评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,703评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,705评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,620评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,995评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,656评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,898评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,639评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,720评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,395评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,982评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,953评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,195评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,907评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,472评论 2 342

推荐阅读更多精彩内容

  • 第1章 Shell和vi 1.1什么是shell 在计算机科学中,Shell俗称壳,用来区别于Kernel(核),...
    福尔摩鸡阅读 856评论 0 1
  • 暖日斜阳 倚靠路边好乘凉。 车水马龙 行人匆匆影不同。
    解放思想放眼世界阅读 226评论 0 0
  • 宝石禅绕我只求好看,老师的宝石技法课越听越不会画,随心吧,自已画得开心即好。
    荣翟阅读 375评论 0 3
  • 我一个人站在寒冷的除夕夜里,盯着手机上黄柳依发来的短信,一时陷入了踌躇。想了一会儿,我才悠悠地叹出了一口气。我决定...
    乔新峥阅读 375评论 3 1
  • 与闺蜜同处一室,醒来彼此道一声早安,真的很幸福!感谢有你!谢谢!谢谢!谢谢! 婷上班前叮嘱我带水果,酸奶,零食!谢...
    Iris若一阅读 343评论 0 1