Git Stash
git stash
会暂时搁置(或暂存)您对工作副本所做的变更,这样您就可以处理其他事情,然后回来重新应用它们。如果您需要快速切换上下文并处理其他事情,但是您正处于代码变更的中间,还没有做好提交的准备,那么暂存很方便。
暂存您的工作
git stash
命令获取您未提交的变更(暂存和未暂存),保存它们以备日后使用,然后将其从工作副本中恢复。例如:
$ git status
On branch main
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
nothing to commit, working tree clean
相关资料
Git 分支
查看解决方案
了解 Bitbucket Cloud 的 Git
此时您可以自由地进行变更、创建新的提交、切换分支和执行任何其他 Git 操作,然后在您准备好后返回重新应用您的暂存。
请注意,暂存是您的 Git 存储库的本地存储库,当您推送时,存储库不会传输到服务器。
重新应用您暂存的变更
您可以使用 git stash pop
重新应用之前存储的变更:
$ git status
On branch main
nothing to commit, working tree clean
$ git stash pop
On branch main
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)
弹出您的暂存会移除暂存中的变更,并将它们重新应用到您的工作副本中。
或者,您可以使用 git stash apply
将变更重新应用到工作副本并将其保存在您的暂存中:
$ git stash apply
On branch main
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
如果您想将相同的暂存变更应用于多个分支,这很有用。
既然您已经了解了暂存的基础知识,那么您需要注意 git stash
的一个注意事项:默认情况下,Git 不会暂存对未跟踪或忽略的文件所做的变更。
暂存未跟踪或忽略的文件
默认情况下,运行 git stash
会暂存:
- 已添加到索引的变更(已暂存的变更)
- 对 Git 当前跟踪的文件所做的变更(未暂存的变更)
但它不会暂存:
- 工作副本中尚未暂存的新文件
- 被忽略的文件
因此,如果我们在上面的示例中添加第三个文件,但不要暂存它(即我们不运行 git add
),git stash
不会将其暂存。
$ script.js
$ git status
On branch main
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
Untracked files:
script.js
添加 -u
选项(或 --include-untracked
)会 让 git stash
同时暂存您未被跟踪的文件:
$ git status
On branch main
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Untracked files:
script.js
$ git stash -u
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
nothing to commit, working tree clean
如需包括对被忽略的文件的变更,您可以在运行 git stash
时选择 -a
选项(或 --all
)。
管理多个暂存
您可以多次暂存,您可以多次运行 git stash
来创建多个暂存,然后使用 git stash list
来查看它们。默认情况下,在您创建暂存的分支和提交的顶部,将暂存简单地标为 "WIP"(正在进行中)。过了一会儿,可能很难记住每个暂存包含什么:
$ git stash list
stash@{0}: WIP on main: 5002d47 our new homepage
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage
为了提供更多背景信息,最好使用 git stash save "message"
在暂存中添加描述注释:
$ git stash save "add style to our site"
Saved working directory and index state On main: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On main: add style to our site
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage
默认情况下,git stash pop
会重新应用最近创建的暂存:stash@{0}
您可以通过传递其标识符作为最后一个参数来选择要重新应用哪个暂存,例如:
$ git stash pop stash@{2}
查看暂存差异
您可以使用 git stash show
查看暂存的摘要:
$ git stash show
index.html | 1 +
style.css | 3 +++
2 files changed, 4 insertions(+)
或者打开 -p
选项(或 --patch
)来查看暂存的完整差异:
$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
部分暂存
您也可以选择仅存储单个文件、一组文件或文件中的单个变更。如果您将 -p
选项(或 --patch
)传递给 git stash
,它会遍历工作副本中每个变更过的“块”,并询问您是否需要暂存:
$ git stash -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
Stash this hunk [y,n,q,a,d,/,e,?]? y
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash this hunk [y,n,q,a,d,/,e,?]? n
您可以单击 ? 获取块命令的完整列表。常用的有:
命令 | 描述 |
---|---|
/ | 描述 用正则表达式搜索块 |
? | 描述 帮助 |
n | 描述 不要暂存这个块 |
q | 描述 退出(任何已选中的块都将暂存) |
s | 描述 把这个块拆分成小块 |
Y | 描述 暂存这个块 |
没有明确的“中止”命令,但是按下 CTRL-C
(SIGINT) 会中止暂存进程。
从您的暂存创建一个分支
如果您的分支上的变更与您暂存中的变更不同,您在弹出或应用暂存时可能会遇到冲突。相反,您可以使用 git stash branch
创建一个新分支,将您的暂存变更应用于:
$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)
这会根据您创建暂存的提交来签出一个新分支,然后将您暂存的变更弹出到这个分支上。
清理您的暂存
如果您决定不再需要特定的暂存,您可以使用 git stash drop
将其删除:
$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)
或者您可以使用以下方法删除所有暂存:
$ git stash clear
git stash 是如何工作的
如果您只是想知道如何使用 git stash
,读到这里就可以了。但是,如果您对 Git(和 git stash
)的幕后工作原理感到好奇,请继续阅读!
暂存实际上是在您的存储库中编码为提交对象。.git/refs/stash
的特殊引用指向您最近创建的暂存,而之前创建的暂存由 stash
引用的引用日志引用。这就是您用 stash@{n}:
引用暂存的原因:您实际上指的是 stash
引用的第 n 个引用日志条目。由于暂存只是一次提交,您可以使用 git log
进行检查:
根据您暂存的内容,单个 git stash
操作会创建两个或三个新的提交。上图中的提交是:
stash@{0}
新提交用于存储运行git stash
时工作副本中的跟踪文件stash@{0}
的第一个父项,即您运行git stash
时在 HEAD 处预先存在的提交stash@{0}
的第二个父项,一个代表您运行git stash
时索引的新提交stash@{0}
的第三个父项,一个代表您运行git stash
时工作副本中未被跟踪的文件的新提交。只有在以下情况下才会创建第三个父项:- 您的工作副本实际上包含未跟踪的文件,以及
- 您在调用
git stash
时指定了--include-untracked
或--all
选项。
git stash
如何将您的工作树和索引编码为提交:
- 在暂存之前,您的工作树可能包含对跟踪文件、未跟踪文件和忽略文件的变更。其中一些变更也可能暂存于索引中。
- 调用
git stash
将对跟踪文件的任何变更编码为 DAG 中的两个新提交:一个用于未暂存的变更,另一个用于暂存索引中的变更。特殊refs/stash
引用已更新为指向他们。
- 使用
--include-untracked
选项还可以将未跟踪文件的任何变更编码为额外提交。
- 使用
--all
选项包括对所有忽略的文件的变更,以及对同一次提交中未跟踪文件的变更。
当您运行 git stash pop
时,上面提交中的变更用于更新您的工作副本和索引,而暂存引用日志会被整理以删除弹出的提交。请注意,弹出的提交不会立即被删除,但确实未来可能会当成垃圾回收。
分享此文章
下一主题
推荐阅读
将这些资源加入书签,以了解 DevOps 团队的类型,或获取 Atlassian 关于 DevOps 的持续更新。