gitの月光宝盒

git作为时下世界最流行的代码版本管理工具,我们无论在工作中还是日常编码时几乎都离不开 git 的使用。但是有时候因为我们自身的误操作,或者其他原来未料到突发事件,需要撤销某个操作或者修改曾经提交的操作,那么我们就需要使用上 git 强大的撤销功能了。

我们在进行撤销操作之前,首先了解两个 git 里面最基本但是很重要的概念:文件状态reflog

1 基础概念

1.1 文件状态(file states)

文件状态(file states)概念是 git 中相比较于以往的 CVSs 类软件不同的地方。按官方描述,文件被追踪之后有三种状态,加上被追踪之前的状态,这里认为文件有4种状态。如下图:

file states

<div style="text-align:center;">(图1-1)</div>

  • untrack -- 文件刚新建,还没有被 git 追踪前的状态。
  • tracked -- 已经被 git 追踪,git 能检测到文件状态是否有改变。(https://git-scm.com/book/en/v2/Getting-Started-Git-Basics)。
  • staged -- 文件(改变)已经进入'暂存'状态,下一次提交会把此改变提交到本地仓库。
  • commited -- 文件(改变)已经提交到本地仓库,但是还没有推送到远程仓库,生成一次文件快照。

Ps:文件快照概念是 git 和其他版本管理软件相区分的重要概念之一。

1.2 reflog

reflog显示整个本地仓储的 commit 记录, 包括所有 branch 的 commit, 已经撤销的 commit, 只要 HEAD 发生了变化, 就会在 reflog 里面看得到。同一个改动,在 reflog 里可能出现多次。reflog 在撤销所有影响了本地仓库的改动时非常有用。

2 使用月光宝盒

2.1 tracked -> untrack

命令git rm --cache <file>

一个新建的文件被记录在 git 中了,但是突然发现我们并不需要把它提交到仓库中,就需要让它回到“自由自在”的状态。比如我刚开始用 mac 的时候,在输入git status命令查看时才发现一不小心就把.DS_Store文件提交到了 git 里面去,这时候就需要让这个意外的文件回到 untrack 状态。

~ $ touch .DS_Store
~ $ git status
On branch master
Untracked files:

    .DS_Store

~ $ git add -N .DS_Store
~ $ git status
On branch master
Changes not staged for commit:

    new file:   .DS_Store

~ $ git rm --cache .DS_Store
rm '.DS_Store'
~ $ git status
On branch master
Untracked files:

    .DS_Store

2.2 staged -> untrack

命令1git rm --cache <file>
命令2git reset HEAD <file>

使用上一个命令,同样可以使一个在 staged 状态的文件回到 untrack 状态,无论文件原来是否已经 tracked
git rm --cache <file>命令还可以使已经暂存的文件回到untrack状态

~ $ git status
On branch master
Changes to be committed:

    new file:   .DS_Store
    modified:   file1
~ $ git rm --cache .DS_Store file1
rm '.DS_Store'
rm 'file1'
~ $ git status
On branch master
Changes to be committed:

    deleted:    file1

Untracked files:

    .DS_Store
    file1

2.3 staged -> tracked

命令git reset HEAD <file>

从暂存态回到追踪态,一般情况下是文件本来存在于 git 版本库中,经过用户修改并且使用git-add命令添加到待提交队列中。如果文件较少,这个过程的撤销意义并不大,因为完全可以把文件修改回原始状态并且再次使用git-add就可以了,但是如果文件较多,就使用命令比较方便了。

~ $ git status
On branch master
Changes to be committed:

    modified:   file1

~ $ git reset HEAD file1
Unstaged changes after reset:
M   file1
~ $ git status
On branch master
Changes not staged for commit:

    modified:   file1

从上面可见,虽然文件从staged回到了tranked,但是本地修改还是保留了,如果加上 --hard 选项,则会让文件回退到最后一次 commit 时的状态,丢弃掉本地修改。

~ $ git status
On branch master
Changes to be committed:

    modified:   file1

~ $ git reset HEAD --hard
HEAD is now at a580a0e init
~ $ git status
On branch master
nothing to commit, working tree clean

2.4 undo commit

命令git reset --option <commit>

想撤销一个 commit 操作其实和撤销 stage 操作一样,就是使用 reset 命令使本地目录回退到项目“曾经的某个状态”,这里的“某个状态”就是指曾经在本地项目做过的操作,可以使用上述提到的 git reflog 查看

~ $ git reflog

a580a0e (HEAD -> master) HEAD@{0}: reset: moving to a580a0e
9b953c1 HEAD@{1}: reset: moving to HEAD@{3}
a580a0e (HEAD -> master) HEAD@{2}: reset: moving to HEAD
a580a0e (HEAD -> master) HEAD@{3}: reset: moving to HEAD
a580a0e (HEAD -> master) HEAD@{4}: reset: moving to HEAD~1
9b953c1 HEAD@{5}: commit: test
a580a0e (HEAD -> master) HEAD@{6}: reset: moving to HEAD~1
eeb881f HEAD@{7}: commit: test
a580a0e (HEAD -> master) HEAD@{8}: reset: moving to HEAD
a580a0e (HEAD -> master) HEAD@{9}: reset: moving to HEAD
a580a0e (HEAD -> master) HEAD@{10}: commit (initial): init

git reset --option <commit> 中的 <commit> 替换为上面输出的第一列的HASH值或者HEAD@{number},即可让项目本地仓库回退到指定的状态,此状态之后的文件变化,会根据 --option 值的不同应用到本地文件中,我们使用 git reset --help可以看到详细的例子介绍

~ $ git reset --help
In these tables, A, B, C and D are some different states of a file. For example, the first line of the first table means that if
a file is in state A in the working tree, in state B in the index, in state C in HEAD and in state D in the target, then "git
reset --soft target" will leave the file in the working tree in state A and in the index in state B. It resets (i.e. moves) the
HEAD (i.e. the tip of the current branch, if you are on one) to "target" (which has the file in state D).

working index HEAD target         working index HEAD
----------------------------------------------------
A       B     C    D     --soft   A       B     D
                          --mixed  A       D     D
                          --hard   D       D     D
                          --merge (disallowed)
                          --keep  (disallowed)

working index HEAD target         working index HEAD
----------------------------------------------------
A       B     C    C     --soft   A       B     C
                          --mixed  A       C     C
                          --hard   C       C     C
                          --merge (disallowed)
                          --keep   A       C     C

working index HEAD target         working index HEAD
----------------------------------------------------
B       B     C    D     --soft   B       B     D
                          --mixed  B       D     D
                          --hard   D       D     D
                          --merge  D       D     D
                          --keep  (disallowed)

working index HEAD target         working index HEAD
----------------------------------------------------
B       B     C    C     --soft   B       B     C
                          --mixed  B       C     C
                          --hard   C       C     C
                          --merge  C       C     C
                          --keep   B       C     C

working index HEAD target         working index HEAD
----------------------------------------------------
B       C     C    D     --soft   B       C     D
                          --mixed  B       D     D
                          --hard   D       D     D
                          --merge (disallowed)
                          --keep  (disallowed)

working index HEAD target         working index HEAD
----------------------------------------------------
B       C     C    C     --soft   B       C     C
                          --mixed  B       C     C
                          --hard   C       C     C
                          --merge  B       C     C
                          --keep   B       C     C

总结

以上所提供的并不是唯一的方法,只是其中一种或多种实现撤销的手段,欢迎一起讨论更多好用的方法。

鉴于 git 的对整个项目做快照的特性,所有操作对于 git 来说都是ADD操作(增加一个“删除”操作,增加一个“修改”操作等),所以我们只需要善用 git resetgit reflog,几乎能完成所有的撤销操作。


参考连接
https://git-scm.com/book/id/v2/Git-Basics-Recording-Changes-to-the-Repository
https://git-scm.com/book/en/v2/Getting-Started-Git-Basics
https://git-scm.com/docs/git-reflog


版权声明:本文为博主原创文章,未经博主允许不得转载,本文首发于xlaoyu

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

推荐阅读更多精彩内容

  • 其实使用git已经有两年多时间了,但是对Git的概念一直懵懵懂懂,平时常用的命令就那么几个,而且大部分的时候都是直...
    Claire_wu阅读 604评论 0 5
  • git init  在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个repo,并在当前...
    懿左左阅读 338评论 0 4
  • Git 是目前最流行的分布式版本控制系统之一。 版本控制指的是,记录每次版本变更的内容和时间等细节,保留各版本之间...
    神齐阅读 1,425评论 0 7
  • 1. GIT命令 git init在本地新建一个repo,进入一个项目目录,执行git init,会初始化一个re...
    江边一蓑烟阅读 799评论 0 0
  • 输入 y ,创建 git_hug 目录No githug directory found, do you wish...
    风花花阅读 1,927评论 0 4