checkout进阶与stash
checkout --讲解
我们先查看下git status
是否正常,然后再编辑test1.txt
增加了no hallo
:
$ cat test1.txt
hello
world
hello world
hello hello hello
no hello
这时候我们再查看一下:
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
发现是处于工作区了,我们使用git checkout --
命令试试:
$ git checkout -- test1.txt
再查看一下:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
nothing to commit, working tree clean
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ cat test1.txt
hello
world
hello world
hello hello hello
这时候就可以发现添加的no hallo
已经不见了,并且git
的状态也恢复正常了
我们这时候还是修改test1.txt
,对其加入no hallo
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ cat test1.txt
hello
world
hello world
hello hello hello
no hello
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
然后执行git add .
,再查看一下:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git add .
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
我们如果再次修改test1.txt
会发生什么了?我们现在只是将工作区的第一次修改的test1.txt
提交到了暂存区,试试吧:
新的修改:must hello
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ vim test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ cat test1.txt
hello
world
hello world
hello hello hello
no hello
must hello
git status
查看:
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
我们这时候再试试git checkout --
:
$ git checkout -- test1.txt
查看内容变化:
$ cat test1.txt
hello
world
hello world
hello hello hello
no hello
发现第一次做的修改no hello
保留下来了的,是保存在缓存区的,而第二次修改的must hello
则没有了
git status
查看状态:
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
总结:git checkout -- test1.txt
作用是:丢弃掉相对于暂存区中最后一次添加文件内容所做的修改
验证:
我们执行git reset HEAD
命令将缓存区的no hallo
放回到工作区:
$ git reset HEAD test1.txt
Unstaged changes after reset:
M test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
再执行git checkout --
:
$ git checkout -- test1.txt
查看内容:
$ cat test1.txt
hello
world
hello world
hello hello hello
查看状态:
$ git status
On branch master
nothing to commit, working tree clean
checkout回退版本
我们原来学过git checkout
切换分支,其实它也可以用来切换版本,但与我们上章所学的git reset --hard
又有不同
先git log
查看一下:
commit 3573a2322e2590fa8abcf6dca93b2ea6b01b9506 (HEAD -> master)
Author: YQHP-YuKi <************@qq.com>
Date: Sun Nov 22 16:02:40 2020 +0800
3hello in test1.txt
commit b38e36d4fb88dcb629c855972eb86e5e9cbdf2b9
Author: YQHP-YuKi <***********@qq.com>
Date: Sun Nov 22 15:58:38 2020 +0800
hello world in test1.txt
commit 9ed5c2398694d005e7abf2468574d0fc91a42189
Author: YQHP-YuKi <***********@qq.com>
Date: Sun Nov 22 15:57:34 2020 +0800
world in test1.txt
commit 61adf63007461e6e5d79b19aa0ff09ff61033d76
Author: YQHP-YuKi <***********@qq.com@qq.com>
Date: Sun Nov 22 15:53:29 2020 +0800
hello test1.txt
假如这时候我们想回到9ed5c
这个版本,我们可以这样做:git checkout
+版本号:
$ git checkout 9ed5c
Note: switching to '9ed5c'.
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:
git switch -c <new-branch-name>
Or undo this operation with:
git switch -
Turn off this advice by setting config variable advice.detachedHead to false
HEAD is now at 9ed5c23 world in test1.txt
翻译:现在你已经进入到了一个游离的状态,你可以四周查看一下,做一些环境的改变,如果你想创建一个新的分支,你可以用git switch -c <new-branch-name>
,现在你的HEAD
不再是指向master
,而是指向 9ed5c23 world in test1.txt
我们查看一下test1.txt
:
$ cat test1.txt
hello
world
查看历史:
$ git log
commit 9ed5c2398694d005e7abf2468574d0fc91a42189 (HEAD)
Author: YQHP-YuKi <*************@qq.com>
Date: Sun Nov 22 15:57:34 2020 +0800
world in test1.txt
commit 61adf63007461e6e5d79b19aa0ff09ff61033d76
Author: YQHP-YuKi <************@qq.com@qq.com>
Date: Sun Nov 22 15:53:29 2020 +0800
hello test1.txt
我们对这个历史版本不做任何操作尝试回到master
试试:
$ git checkout master
Previous HEAD position was 9ed5c23 world in test1.txt
Switched to branch 'master'
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git branch
* master
发现又正常回到了master
且没有任何多的分支增加,这几次操作的图片讲解:
我们最先前是在master
,执行git checkout 9ed5c
后,HEAD
不再指向master
,而是指向9ed5c
,所以只能看到先前的两次提交信息,看不到在此版本与master
之间的任何提交信息
那我们再回到9ed5c
,并对其中的test1.txt
进行改动试试:
增加了checkout back
$ cat test1.txt
hello
world
checkout back
再尝试返回到master
:
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
test1.txt
Please commit your changes or stash them before you switch branches.
Aborting
但是出现了报错:错误,你当前的改变文件将会重写test1.txt
,请提交你的改变或者stash
他们在你改变分支前
那我们commit
一下:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile ((9ed5c23...))
$ git add .
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile ((9ed5c23...))
$ git commit -m "commit on 9ed5c again"
[detached HEAD 00fd224] commit on 9ed5c again
1 file changed, 1 insertion(+)
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile ((00fd224...))
这时候就发生了变化,我们从9ed5c23
变为了00fd224
,查看历史看看:
$ git log
commit 00fd224b50c9ed5390257617220ad0e35064571b (HEAD)
Author: YQHP-YuKi <**************@qq.com>
Date: Wed Nov 25 09:31:10 2020 +0800
commit on 9ed5c again
commit 9ed5c2398694d005e7abf2468574d0fc91a42189
Author: YQHP-YuKi <**************@qq.com>
Date: Sun Nov 22 15:57:34 2020 +0800
world in test1.txt
commit 61adf63007461e6e5d79b19aa0ff09ff61033d76
Author: YQHP-YuKi <**************@qq.com@qq.com>
Date: Sun Nov 22 15:53:29 2020 +0800
hello test1.txt
这时候的状态图:
我们再尝试去切换回到master
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile ((00fd224...))
$ git checkout master
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
00fd224 commit on 9ed5c again
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 00fd224
Switched to branch 'master'
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
这时候就只是警告了:警告你正在离开一个落后的commit,没有与你的分支有任何联系,提交信息为: 00fd224 commit on 9ed5c again,如果你想保存就创造一个新的branch,这时候也许是个好时间去创造,命令为: git branch
这时候的状态图:
创建一个新的分支:
$ git branch newcommot 00fd224
查看下:
$ git branch
* master
newcommot
我们切换到newcommit
看看:
$ git log --graph
* commit 00fd224b50c9ed5390257617220ad0e35064571b (HEAD -> newcommot)
| Author: YQHP-YuKi <1465722762@qq.com>
| Date: Wed Nov 25 09:31:10 2020 +0800
|
| commit on 9ed5c again
|
* commit 9ed5c2398694d005e7abf2468574d0fc91a42189
| Author: YQHP-YuKi <1465722762@qq.com>
| Date: Sun Nov 22 15:57:34 2020 +0800
|
| world in test1.txt
|
* commit 61adf63007461e6e5d79b19aa0ff09ff61033d76
Author: YQHP-YuKi <1465722762@qq.com@qq.com>
Date: Sun Nov 22 15:53:29 2020 +0800
hello test1.txt
可以看到我们在9ed5c
上面的新提交00fd2
这个已经成为了一个新的分支
此时的状态图:
总结:
- 通过
checkout
进行版本回退会造成游离的提交对象链,需要额外创建一个分支进行保存 - 因此,使用
checkout
进行版本回退的思路为,先切换到想要回退的提交版本,再删除进行版本回退的分支dev
,最后,创建一个新的dev
分支指向游离的提交对象链,完成分支dev
的版本回退 - 只要有分支指向,提交就不会被丢弃
stash
我们在msater
执行git status
检查一下:
master:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
nothing to commit, working tree clean
然后创建一个新的分区test
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git checkout -b test
Switched to a new branch 'test'
然后回到master
上修改test1.txt
,并将其提交:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ vim test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git commit -am "stash in master"
[master 69d720d] stash in master
1 file changed, 1 insertion(+)
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git status
On branch master
nothing to commit, working tree clean
查看下修改的test1.txt
:
$ cat test1.txt
hello
world
hello world
hello hello hello
stash in master
这时候我们回到test
分支,也对test1.txt
进行修改,并进行查看一下:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
status in test
假如这时候你公司叫你回到master
进行一个另一个文件的修改或者版本控制,这时候你想回到master
分支:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
test1.txt
Please commit your changes or stash them before you switch branches.
Aborting
翻译:你本地的改变的test1.txt
文件会被checkout
所重写覆盖,请将文件进行提交或者stash
在你改变分支之前
我们尝试将文件从工作区放进缓存区试试:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git add .
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git status
On branch test
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
test1.txt
Please commit your changes or stash them before you switch branches.
Aborting
但是还是出现这个报错,说明无论是工作区还是缓存区的修改都会被checkout
所覆盖,原因如图:
我们最先前的msater
已经做出了改变,但这个test
分支还是在第一次的master
的分支上分离出来的,是处于一个游离的状态,所以现在要切换到现在的msater
,就会被现在的master
所覆盖
这种情况在工作日常开发中很常见,但在develop
分支上开发新功能的时候,master
分支出现紧急情况需要切换回去进行修复,但是当前分支的新功能还没完全开发完全,贸然切换分支,会导致所做的修改而被覆盖,而且也不可以随意的commit
,因为你这分支版本还是处于测试版本,不能随意提交到版本库中,这时候你就需要用到stash
我们将缓存区的test1.txt
文件放回到工作区:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git reset HEAD test1.txt
Unstaged changes after reset:
M test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git status
On branch test
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
然后执行git stash
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash
Saved working directory and index state WIP on test: 3573a23 3hello in test1.txt
查看下test1.txt
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
发现所做的修改stash in test
没有了,这时候我们再切换到master
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git checkout master
Switched to branch 'master'
发现没问题了,再切换到test
分支并且查看test1.txt
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (master)
$ git checkout -
Switched to branch 'test'
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
发现我们所做的修改还是没有,那stash in test
到底在哪了?
- 其实通过了
git stash
将test
分支上工作区或暂存区中的修改,提交到了stash
区域进行保存,并将test
分支退回到修改前的状态,如下图所示:
- 切换到
master
分支时test
分支上的修改依旧会被覆盖,所以,再次回到test
分支时需要从stash
区域中恢复切换分支前所保存的修改
查看stash日志
我们可以通过git stash list
查看stash
的版本日志:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash list
stash@{0}: WIP on test: 3573a23 3hello in test1.txt
注:后面的WIP
是working in process
的意思,表示的是正在进行的工作
这样就看到我们先前stash in test
的日志了,编号为stash@{0}
,我们也可以对stash
日志进行每个日志命名,例如我们再次修改test1.txt
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ vim test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
stash try again
通过参数save
可以命名,例如:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash save 'stash try again'
Saved working directory and index state On test: stash try again
再git stash list
查看一下:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash list
stash@{0}: On test: stash try again
stash@{1}: WIP on test: 3573a23 3hello in test1.txt
这样我们就看到1
的第一提交,0
第二次提交的try again
想要恢复stash
所做的修改前模样,主要有三种方法:
git stash pop
git stash apply
git stash apply stash@{number}
git stash pop
我们使用git stash pop
看看:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash pop
On branch test
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (6e4d554894d1db504cf525db30b3f7196ce1478f)
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
stash try again
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash list
stash@{0}: WIP on test: 3573a23 3hello in test1.txt
发现第二次修改的try again stash
恢复回来了,git stash list
中的第二次历史信息没了,而且状态也变为工作区了
git stash pop
作用:恢复并删除stash
中存储的最新修改
git stash apply
我们再使用git stash apply
试试:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash apply
On branch test
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: test1.txt
no changes added to commit (use "git add" and/or "git commit -a")
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
stash try again
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash list
stash@{0}: On test: try again stash
stash@{1}: WIP on test: 3573a23 3hello in test1.txt
可以发现跟pop
相比,也是恢复到了工作区,但是git stash list
中的历史记录还是存在
git stash apply
:恢复但不删除stash
中存储的最新修改
如果我们想删除git stash list
中的记录,我们需要手动删除,命令是:git stash drop stash@{number}
,例:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash drop stash@{0}
Dropped stash@{0} (8307e8403059797eed5d2c4f1356649146e167d1)
再查看一下list
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash list
stash@{0}: WIP on test: 3573a23 3hello in test1.txt
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
stash try again
就发现没了,而且文件也改回来了,如果这时候我们使用git stash pop
,会发生什么了?
$ git stash pop
error: Your local changes to the following files would be overwritten by merge:
test1.txt
Please commit your changes or stash them before you merge.
Aborting
The stash entry is kept in case you need it again.
这时候又出现要求你提交要不就stash
的报错,那我们进行提交:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git commit -am 'apply stash'
[test a5300dd] apply stash
1 file changed, 1 insertion(+)
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git status
On branch test
nothing to commit, working tree clean
我们再执行git stash pop
:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ git stash pop
Auto-merging test1.txt
CONFLICT (content): Merge conflict in test1.txt
The stash entry is kept in case you need it again.
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
<<<<<<< Updated upstream
stash try again
=======
status in test
>>>>>>> Stashed changes
这时候发生了合并冲突,这是因为,stash
中保存的每一次修改代表的都是一个版本:
- 如上图所示,在
test
分支上,进行第一次修改后,通过git stash
将该修改作为修改0
保存到stash
中,此时分支中的文件并没有发生改变 - 进行第二次修改后,通过
git stash
将修改作为修改1
保存到stash
中,分支中的文件依旧没有发生改变,此时的stash
中相当于保存着同一分支上两个修改后的版本 - 此时通过
git stash apply
取出0
,与test
分支进行合并,再通过git stash pop
取出1,再次与test
分支进行合并,两个版本合并自然会发生冲突
如果想解决冲突,则vim
修改文件即刻:
A@DESKTOP-6DP8MG1 MINGW64 /e/Gitfile (test)
$ cat test1.txt
hello
world
hello world
hello hello hello
status in test
git stash apply stash@{0}
指定恢复的版本,就跟git reset
指定log
一样
总结:
git stash pop
:恢复并删除stash
中存储的最新修改git stash apply
:恢复但不删除stash
中存储的最新修改git stash apply stash@{0}
:恢复但不删除stash
中存储的特定提交