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

9.1 恢复保存的进度git

查看第五章保存的进度:app

$ 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 <file>..." to unstage)

        new file:   a/b/c/hello.txt

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:   welcome.txt

Dropped refs/stash@{0} (eca70a6e0ecccaddf3641263eb341c4541779ae9)

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

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   a/b/c/hello.txt

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:   welcome.txt

对找回进度的工做区作如下处理:3d

(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)撤销以前的提交,工做区和暂存区的状态也都维持在原来的状态:code

$ git reset --soft HEAD^

$ git log -1 --pretty=oneline
0463e7ae492200b77525642fb77d8f8fa03913c1 Merge commit '64cc27237'

$ git status -s
A  a/b/c/hello.txt
 M welcome.txt

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

$ git add welcome.txt

$ git status -s
A  a/b/c/hello.txt
M  welcome.txt

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

$ git reset HEAD a/b/c

$ git status -s
M  welcome.txt
?? a/

(5)将全部内容存暂存区中撤出:it

$ git reset
Unstaged changes after reset:
M       welcome.txt

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

$ git checkout -- welcome.txt

$ git status
On branch master
Untracked files:
  (use "git add <file>..." 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命令

一、git stash

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

二、git stash list

显示进度列表。

三、git stash pop [--index] [<stash>]

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

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

若是带有选项--index除了恢复工做区的文件外,还尝试恢复暂存区。

四、git stash [save [--patch] [-k|--[no-] keep-index] [-q|--quiet] [<message>] ]

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

git stash save "message..."

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

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

五、git stash apply [--index] [<stash>]

除了不删除恢复的进度以外,其他和git stash pop命令同样。

六、git stash drop [<stash>]

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

七、git stash clear

删除全部存储的进度。

八、git stash branch <branchname> <strach>

基于进度建立分支。

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
A  hack-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.txt  new-commit.txt  welcome.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@[<n>]格式,与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 197121  41 七月 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 <ivanjz93@163.com> 1468849531 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468849531 +0800
| |
| |     WIP on master: 0463e7a Merge commit '64cc27237'
| |
| * commit de586678f3ac0d423a469b6e26968741b6e46344
|/  tree 7032578d4dd41c43b4e62c8806e4b7ad3f9a54e6
|   parent 0463e7ae492200b77525642fb77d8f8fa03913c1
|   author jiangzhi <ivanjz93@163.com> 1468849531 +0800
|   committer jiangzhi <ivanjz93@163.com> 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 <ivanjz93@163.com> 1468831199 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468831199 +0800
| |
| |     On master: hack-1: hacked welcome.txt, newfile hack-1.txt
| |
| * commit 7b3bef783f4d0900b185c4ba4b33646a1090660a
|/  tree 9c34579bf4f5504b9b0376097814d5c1cdb8bbdc
|   parent 0463e7ae492200b77525642fb77d8f8fa03913c1
|   author jiangzhi <ivanjz93@163.com> 1468831198 +0800
|   committer jiangzhi <ivanjz93@163.com> 1468831198 +0800
|
|       index on master: 0463e7a Merge commit '64cc27237'
|
*   commit 0463e7ae492200b77525642fb77d8f8fa03913c1
|\  tree ad4eca82e587a477b91a4f7bbfef97c7921e52cc
| | parent 1ce417a21fcd936e333db5f56a79a04ae2785a08
| | parent 64cc27237267d702e31e34fe0b75db97f5171001
| | author jiangzhi <ivanjz93@163.com> 1468822001 +0800
| | committer jiangzhi <ivanjz93@163.com> 1468822001 +0800
| |     Merge commit '64cc27237'

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

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

$ git stash apply stash@{1}
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   hack-1.txt

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:   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
相关文章
相关标签/搜索