《Git权威指南》读书笔记 第九章 恢复进度

2016-07-19 16:44:58来源:oschina作者:一万人点击

9.1 恢复保存的进度


查看第五章保存的进度:


$ git stash list
stash@{0}: WIP on master: 326f237 which version checked in?

恢复进度:


$ git stash pop
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: a/b/c/hello.txt
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: welcome.txt
Dropped refs/stash@{0} (eca70a6e0ecccaddf3641263eb341c4541779ae9)

查看工作区状态,进度已经找回了:


$ git status
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: a/b/c/hello.txt
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: welcome.txt

对找回进度的工作区做以下处理:


(1)对当前的暂存区进行提交:


$ git commit -m "add new file: a/b/c/hello.txt, but leave welcome.txt alone"
[master 9e5eaa3] add new file: a/b/c/hello.txt, but leave welcome.txt alone
1 file changed, 2 insertions(+)
create mode 100644 a/b/c/hello.txt
$ git status -s
M welcome.txt

(2)撤销之前的提交,工作区和暂存区的状态也都维持在原来的状态:


$ git reset --soft HEAD^
$ git log -1 --pretty=oneline
0463e7ae492200b77525642fb77d8f8fa03913c1 Merge commit '64cc27237'
$ git status -s
Aa/b/c/hello.txt
M welcome.txt

(3)将welcome.txt的修改提交到暂存区:


$ git add welcome.txt
$ git status -s
Aa/b/c/hello.txt
Mwelcome.txt

(4)将a/b/c/hello.txt撤出暂存区:


$ git reset HEAD a/b/c
$ git status -s
Mwelcome.txt
?? a/

(5)将所有内容存暂存区中撤出:


$ git reset
Unstaged changes after reset:
Mwelcome.txt

(6)清除welcome.txt个改动:


$ git checkout -- welcome.txt
$ git status
On branch master
Untracked files:
(use "git add ..." to include in what will be committed)
a/
nothing added to commit but untracked files present (use "git add" to track)

(7)删除目录a,删除本地多余的目录和文件,可以使用git clean命令。先运行测试命令查看哪些文件和目录会被删除以免造成误删:


$ git clean -nd
Would remove a/

使用-f参数强制删除文件和目录:


$ git clean -fd
Removing a/

9.2 git stash命令


1、git stash


保存当前的工作进度,会分别对暂存区和工作区的状态进行保存;


2、git stash list


显示进度列表。


3、git stash pop [--index] []


如果不使用任何参数,会恢复最新保存的工作进度,并将恢复的工作进度从存储的工作进度列表中清除。


如果提供参数(来自于git stash list显示的列表),则从该中恢复。恢复完毕也将从进度列表中删除


如果带有选项--index除了恢复工作区的文件外,还尝试恢复暂存区。


4、git stash [save [--patch] [-k|--[no-] keep-index] [-q|--quiet] [] ]


这条命令实际上是第一条git stash命令的完整版。如果需要在保存进度的时候添加说明,必须使用如下格式:


git stash save "message..."

使用参数--patch会显示工作区和HEAD的差异,通过对差异文件的编辑决定在进度中最终要保存的工作区的内容,通过编辑差异文件可以在进度中排除无关内容。


使用-k或--keep-index参数,在保存进度后不会将暂存区重置。默认会将暂存区和工作区强制重置。


5、git stash apply [--index] []


除了不删除恢复的进度之外,其余和git stash pop命令一样。


6、git stash drop []


删除一个存储的进度。默认删除最新的进度。


7、git stash clear


删除所有存储的进度。


8、git stash branch


基于进度创建分支。


9.3 git stash深入


在执行git stash命令时,Git实际调用了一个脚本文件实现相关的功能,这个脚本的文件名是git-stash。使用下面的命令查看git-stash的安装位置:


$ git --exec-path
C:/Program Files/Git/mingw64/libexec/git-core

这个目录下包含了Git命令脚本,最初这些命令都是用Shell或Perl脚本语言开发的,在Git发展中一些对运行效率要求高的命令用C语言改写。在Git 1.7.4版本之前git-stash还是使用Shell脚本开发的。


查看当前的进度保存列表是空的:


$ git stash list

在工作区做一些改动:


$ echo Bye-Bye. >> welcome.txt
$ echo hello. > hack-1.txt
$ git add hack-1.txt
$ git status -s
Ahack-1.txt
M welcome.txt

执行git stash保存工作进度:


$ git stash save "hack-1: hacked welcome.txt, newfile hack-1.txt"
Saved working directory and index state On master: hack-1: hacked welcome.txt, newfile hack-1.txt
HEAD is now at 0463e7a Merge commit '64cc27237'
$ git status -s
$ ls
detached-commit.txtnew-commit.txtwelcome.txt

保存完成后工作区恢复了修改前的原貌(实际上用了git reset --hard HEAD命令),文件welcome.txt的修改不见了,文件hack-1.txt整个不见了。


再做一个修改,并尝试保存进度:


$ echo fix. > hack-2.txt
$ git stash
No local changes to save

进度保存失败。可见暂存区没有更新不能保存进度。


执行添加操作后再执行git stash命令:


$ git add hack-2.txt
$ git stash
Saved working directory and index state WIP on master: 0463e7a Merge commit '64cc27237'
HEAD is now at 0463e7a Merge commit '64cc27237'

工作区又恢复了原状。查看进度保存情况:


$ git stash list
stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt

每个进度的标识都是stash@[]格式,与reflog的格式很相似。实际上,git stash就是用前面介绍的引用和引用变更日志(reflog)来实现的。有关进度的文件:


$ ls -l .git/refs/stash .git/logs/refs/stash
-rw-r--r-- 1 x250 197121 360 七月 18 21:45 .git/logs/refs/stash
-rw-r--r-- 1 x250 19712141 七月 18 21:45 .git/refs/stash

使用git reflog可以查看进度情况:


$ git reflog show refs/stash
04cae38 refs/stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
43f13c7 refs/stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt

对照git reflog的结果和前面git stash list的结果,可以肯定git stash保存进度,实际上会将进度保存在引用refs/stash所指向的提交中。多次的进度保存,实际上相当于引用refs/stash一次又一次的变化(refs/stash只记录一次进度的ID),而refs/stash引用的变化由reflog(.git/logs/refs/stash)所记录下来。


如何在引用refs/stash中同时保存暂存区的进度和工作区中的进度?


查看引用refs/stash的提交历史:


$ git log --graph --pretty=raw refs/stash -2
* commit 04cae38d64c6c6cc7e7421c08349c8a3b75ae7dd
|/tree 7032578d4dd41c43b4e62c8806e4b7ad3f9a54e6
| | parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| | parent de586678f3ac0d423a469b6e26968741b6e46344
| | author jiangzhi 1468849531 +0800
| | committer jiangzhi 1468849531 +0800
| |
| | WIP on master: 0463e7a Merge commit '64cc27237'
| |
| * commit de586678f3ac0d423a469b6e26968741b6e46344
|/tree 7032578d4dd41c43b4e62c8806e4b7ad3f9a54e6
| parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| author jiangzhi 1468849531 +0800
| committer jiangzhi 1468849531 +0800
|
|index on master: 0463e7a Merge commit '64cc27237'

从提交历史中可以看到进度保存的最新提交时一个合并提交。最新的提交说明中有WIP字样(Work In Proress),代表了工作区进度。最新提交的第二个父提交有index on master标记,说明这个提交代表暂存区的进度。


但提交历史中的两个提交都指向了同一个树,这是因为最后一次做进度保存时工作区相对暂存区没有改变。


第一次进度的保存工作区、暂存区和版本库的各不相同。第一次进度保存可以使用reflog中的语法,即用refs/stash@{1}来访问,也可以简写成stash@{1}。


$ git log --graph --pretty=raw stash@{1} -3
* commit 43f13c7c4b13f480032c64b9375f97d16931ba35
|/tree 3cd11ce48979a5f97e28304b1237cfb6d4a8cf7e
| | parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| | parent 7b3bef783f4d0900b185c4ba4b33646a1090660a
| | author jiangzhi 1468831199 +0800
| | committer jiangzhi 1468831199 +0800
| |
| | On master: hack-1: hacked welcome.txt, newfile hack-1.txt
| |
| * commit 7b3bef783f4d0900b185c4ba4b33646a1090660a
|/tree 9c34579bf4f5504b9b0376097814d5c1cdb8bbdc
| parent 0463e7ae492200b77525642fb77d8f8fa03913c1
| author jiangzhi 1468831198 +0800
| committer jiangzhi 1468831198 +0800
|
|index on master: 0463e7a Merge commit '64cc27237'
|
* commit 0463e7ae492200b77525642fb77d8f8fa03913c1
|/tree ad4eca82e587a477b91a4f7bbfef97c7921e52cc
| | parent 1ce417a21fcd936e333db5f56a79a04ae2785a08
| | parent 64cc27237267d702e31e34fe0b75db97f5171001
| | author jiangzhi 1468822001 +0800
| | committer jiangzhi 1468822001 +0800
| | Merge commit '64cc27237'

第一个代表保存时工作区的状态(原工作区),第二个代表保存时暂存区的状态(原暂存区),第三个代表保存时版本库的状态(原基线)。


用stash@{1}来恢复进度:


$ git stash apply stash@{1}
On branch master
Changes to be committed:
(use "git reset HEAD ..." to unstage)
new file: hack-1.txt
Changes not staged for commit:
(use "git add ..." to update what will be committed)
(use "git checkout -- ..." to discard changes in working directory)
modified: welcome.txt

显示进度列表,然后清空进度列表:


$ git stash list
stash@{0}: WIP on master: 0463e7a Merge commit '64cc27237'
stash@{1}: On master: hack-1: hacked welcome.txt, newfile hack-1.txt
$ git stash clear

清空后stash相关的引用和reflog被删除了:


$ ls -l .git/refs/stash .git/logs/refs/stash
ls: cannot access '.git/refs/stash': No such file or directory
ls: cannot access '.git/logs/refs/stash': No such file or directory

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台