stash的字面意思:隐藏,储藏
当我们以多人协同工作的方式基于同一个github仓库进行开发时,免不了遇到多人同时在本机对同一文件进行编辑的情况出现。
看一个具体的场景,当我使用git pull时,收到错误提示:我本地修改了SandboxTest.java这个文件,而此时远端仓库里,已经有另一位同事从本地提交了对该文件的修改,而我俩对这个文件的编辑有冲突之处,因此提示我先“stash my local change”:
使用git stash,将我对该文件的修改暂存到stash区域:
此时我就可以顺利地执行git pull命令,先将我同事的最新代码从远端拖到本地。
然后执行git stash pop,将我自己本地的修改从stash区域取出来:
此时当然会有冲突出现,因为我们对同一文件做了修改,冲突的地方会显示在编辑器里,此时手动处理完这些冲突,重新提交即可。
git stash
命令是 Git 中用于临时保存当前工作目录的修改的一个非常强大的工具。这个命令会将未提交的工作内容保存到一个栈(stack)中,以便用户可以清空当前工作目录,然后稍后再恢复这些修改。对开发者来说,当需要切换分支或者拉取最新代码但又不希望丢失当前工作进度时,git stash
是一个非常有用的命令。
工作原理
git stash
命令会将当前工作目录和暂存区中的修改保存起来,并将其从工作目录中清除。保存的修改就像是一个堆栈中的对象,后进先出(LIFO)。每次执行 git stash
,都会在栈顶保存当前的工作状态。
基本用法
最常见的 git stash
命令是 git stash
和 git stash pop
。
git stash
: 将当前的暂存区和工作目录中的修改保存到栈中,并将这些修改从工作目录和暂存区中清除。git stash pop
: 恢复最近一次保存的修改,并从栈中移除这个保存的状态。
示例
让我们通过一些示例来展示 git stash
的基本用法和一些高级用法:
场景 1:保存当前工作进度
假设你正在工作中,对某些文件进行了修改,但突然需要切换到其他分支。此时,你不希望把当前的修改提交到版本控制中,但又不想丢失这些修改。你可以使用 git stash
来保存这些修改。
$ git status
On branch feature
Changes not staged for commit:
modified: file1.txt
modified: file2.txt
$ git stash
Saved working directory and index state WIP on feature: a1b2c3d Update README
HEAD is now at a1b2c3d Update README
$ git status
On branch feature
nothing to commit, working tree clean
此时,file1.txt
和 file2.txt
的修改已经被暂存并从工作目录中清除了。你可以自由地切换分支:
$ git checkout main
Switched to branch 'main'
当你完成其他工作后,可以回到原来的分支并恢复刚才的修改:
$ git checkout feature
Switched to branch 'feature'
$ git stash pop
On branch feature
Changes to be committed:
modified: file1.txt
modified: file2.txt
Dropped refs/stash@{0} (96b8c9e827e7f2c1e9ded2fe61eb9802f0ab3bab)
场景 2:查看已保存的修改列表
对于复杂的开发流程,你可能会多次使用 git stash
来保存不同阶段的修改。git stash list
命令可以查看当前栈中所有保存的修改。
$ git stash list
stash@{0}: WIP on feature: a1b2c3d Update README
stash@{1}: WIP on feature: e5f6g7h Fix bug in login
stash@{2}: WIP on main: i8j9k0l Add unit tests
场景 3:恢复指定的修改
如果你希望恢复特定的一次修改,可以使用 git stash apply
来应用特定的 stash 而不从栈中移除它。通过指定索引,可以恢复某次特定的修改。
$ git stash apply stash@{1}
On branch feature
Changes to be committed:
modified: login.js
modified: utils.js
这种方式可以保留原来的 stash,从而方便日后再次应用。
高级用法
git stash
命令有一些附加选项,可以处理更为复杂的场景。
仅保存未暂存的修改: 有时你可能只想保存工作目录中未暂存的修改,而不包含暂存区的修改。此时可以使用
git stash --keep-index
。$ git stash --keep-index
这个命令将会把未暂存的修改保存到 stash,同时保留暂存区中的修改。
指定描述信息:为了更好地管理保存的修改,可以在
git stash
时添加描述信息,方便以后查找。$ git stash save "WIP: Working on user authentication"
管理多个 stash:尽管
git stash pop
会自动从栈中移除一次保存的状态,但有时候你可能希望保留这个状态。你可以使用git stash apply
来应用而保留它。如果后来你确定不再需要这个保存的修改,可以使用git stash drop
来删除。$ git stash drop stash@{0}
删除所有 stash:在完成所有工作后,你可能希望清空所有 stash。此时可以使用
git stash clear
。$ git stash clear
场景 4:合并冲突
在恢复 stash 时,可能会碰到合并冲突。这种情况下,Git 会提示并让你手动解决冲突。解决完冲突后,你可以继续使用 git add
来暂存解决冲突的文件,然后使用 git commit
来完成合并。
$ git stash pop
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
...
$ git status
On branch feature
You have unmerged paths.
...
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: file1.txt
...
$ vim file1.txt # 手动解决冲突
$ git add file1.txt
$ git commit -m "Resolve merge conflict in file1.txt"
场景 5:Git 同 Github 的交互
在使用 git stash
命令时,可能很多人好奇它在客户端同 Github 交互的情景下表现如何。实际上,git stash
是一个纯本地操作的命令,它不会涉及到远程仓库的交互。这意味着,无论你如何使用 git stash
,它都不会影响你的远程仓库。
例如,当你在本地执行 git stash
后,你可以继续进行其他的远程操作如 git fetch
, git pull
, git push
等等,这些操作都不会受 git stash
的任何影响。同样的,你可以在恢复 stash 之后继续对代码进行处理,然后再进行提交和推送。
$ git stash
$ git fetch origin main
$ git checkout main
$ git merge FETCH_HEAD
# 解决冲突或者进行其他操作
$ git push origin main
$ git checkout feature
$ git stash pop
这展示了如何在 stash 状态后继续进行远程仓库的操作,显示了 git stash
的灵活性和无缝集成能力。
详细说明
工作原理
Git 的设计核心是一个简单又高效的文件系统——Object Database,包含了 blobs,trees 和 commits 等对象。每次你运行 git stash
时,Git 实际上做了如下操作:
- 创建一个新的 commit 表示工作目录和暂存区的状态。
- 创建另一个 commit 表示暂存区的状态。
- 使用这些 commits 来创建一个新的 stash-entry。
- 将当前状态恢复到 HEAD(在
git stash
时,暂存区和工作目录会变为空)。
这种机制背后体现了 Git 的强大的 snapshot 容器和数据存储模型。不仅使得 git stash
的操作几乎瞬间完成,还确保整个操作是完全反向可追踪的。
保存未跟踪文件
git stash
默认不包括未跟踪的文件。如果你希望 stash 中包含这些未跟踪的文件,你需要使用 -u
选项。
$ touch newfile.txt
$ git status
On branch feature
Untracked files:
(use "git add <file>..." to include in what will be committed)
newfile.txt
$ git stash -u
在执行 git stash -u
后,newfile.txt
也会被暂存起来。
忽略遗漏的文件
有时你不想将忽略的文件(在 .gitignore
中定义的文件)包括在 stash 中。这时可以使用 git stash -a
来将这些文件也包括进去。
$ touch ignoredfile.txt
$ git status
On branch feature
Ignored files:
(use "git add -f <file>..." to include in what will be committed)
ignoredfile.txt
$ git stash -a
这样,ignoredfile.txt
也会被暂时保存起来。
检查 stash 中的内容
为了更加精确地管理存储的修改,可以使用 git stash show
以及 git stash show -p
命令来查看具体的差异。
$ git stash show
file1.txt | 2 ++
file2.txt | 4 ++--
$ git stash show -p
diff --git a/file1.txt b/file1.txt
index 83db48f..bf280ff 100644
--- a/file1.txt
+++ b/file1.txt
@@ -1,3 +1,5 @@
...
diff --git a/file2.txt b/file2.txt
index 83db48f..bf280ff 100644
--- a/file2.txt
+++ b/file2.txt
@@ -1,6 +1,8 @@
...
git stash show
会显示一个简要的差异信息,而 git stash show -p
则提供详细的文件差异内容。
总结
通过以上的详细阐述和示例,可以看到 git stash
是一个非常灵活和强大的工具,适用于各种开发场景下的临时保存和恢复工作进度。当我们需要在不同工作状态之间快速切换时,git stash
提供了无缝且高效的操作方式。
从基础用法到高级管理,再到与 Github 的交互,git stash
都表现出简洁和强大的一面。作为开发人员,熟练掌握这个命令可以极大提高工作效率,使你能够更加灵活地应对日常工作中的各种挑战。无论你是在处理短期的修复任务,还是在进行长期的功能开发,git stash
都是你不可或缺的得力工具。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。