Git stash 实战 - 代码没写完,想要切到其他分支,除了临时 commit 还有什么办法

11,878 阅读4分钟

Git 的 stash 功能,顾名思义,就是为了存储代码。假设你正在分支 feature/make-bug 尽情创作,刚修改了一半的代码,你领导忽然告诉你在版本分支 v1.0.0 有个紧急 bug 要你修复。像我刚用 Git 不久的时候,下意识直接切换分支 git checkout v1.0.0,这么做的话,就会有两种后果:

  1. 分支切换失败,git 报错。
error: Your local changes to the following files would be overwritten by checkout:
        service.py
Please commit your changes or stash them before you switch branches.
Aborting
  1. 修改的文件会被带到目标分支。

这里先不追究造成这两种情况的原因。如果不使用 stash,怎么能正确切换到 v1.0.0 分支呢?有两种方式:

  1. feature/make-bug 使用 commit 提交修改,然后切换到 v1.0.0 修改完 bug 后,再切回 feature/make-bug 继续开发,如果不愿意保留上次的临时 commit 记录,则执行 git reset HEAD^ 来完成
  2. 手动将修改的文件文件保存在 git 工作空间之外。

两种都不是好方法,第一种很不灵活,而且还为未完成的工作生成一个 commit。第二种手动复制粘贴更不是好主意。

相比于第一种方法,git stash 可以直接将未提交的修改保存在本地,并允许你做其他的修改,执行其他的 git 操作,比如切到其他分支。当你需要的时候,可以再将 stash 存储过的修改还原。

如何使用 git stash

对于上例,下面是当你使用 git stash 的执行步骤:

  1. 确保文件已经保存,通常 IDE 会自动保存好。
  2. 执行 git stash 存储当前修改。
  3. 切换到 v1.0.0 分支。
  4. v1.0.0 分支修改 bug,并提交修改。
  5. 切换回到 feature/make-bug 分支。
  6. 执行 git stash pop 命令还原存储的修改。

原理上,Git stash 会将代码存储在工程的工作目录 .git/refs/stash 中, 并且并不会被 git push 推送到远程。

Git stash 是能帮你完好保存好稍后可能用到的代码,并且快速清理工作目录的工具。

如何创建一个 stash

最简单的命令就是:

$ git stash
Saved working directory and index state WIP on master: 83a38ba Merge branch 'feature/make-bug'

默认情况下,git stash 存储没有 commit 的修改。不会存储未跟踪的文件(刚新建没有被 add 的文件)与 ignored 文件,一般来说是不需要这这种文件的。当你确实需要时,可以通过 git stash 的额外的参数来控制:

  • git stash -u 或者 git stash --include-untracked :表示存储未跟踪的文件。
  • git stash -a 或者 git stash --all :表示存储为跟踪与 ignored 的文件。

查看你的 stash

使用 git stash list 查看现在所有的 stash,stash 是通过堆栈(后进先出)的顺序存储的。如下所示:

$ git stash list
stash@{0}: WIP on master: 83a38ba Merge branch 'feature/make-bug'

默认 Git 会为 stash 添加默认描述,如上, 有 WIP 文本(正在工作并编写的代码)、分支名、commit 号,上一个提交的描述。但是这提供的信息不太友好,当有多个 stash 的时候,也难以区分,不利于记忆,这时候你可以使用命令 git stash save <description> 自定义 stash 描述:

$ git stash save '添加用户删除 dao' 
Saved working directory and index state On master: 添加用户删除 dao

$ git stash list
stash@{0}: On master: 添加用户删除 dao
stash@{1}: WIP on master: 83a38ba Merge branch 'feature/make-bug'

恢复 stash 改动

你可以使用  git stash applygit stash pop 恢复 stash 的存储。直接执行这两个命令,会恢复栈顶的的 stash(即 stash@{0} 最后保存的 stash)到工作目录。 两者不同的是,pop 会移除堆栈中的 stash,而 apply 不会。

$ git stash pop 
On branch master
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:   dao.py

no changes added to commit (use "git add" and/or "git commit -a")

当你需要恢复最近的 stash 的时候, 直接 pop 是最方便的。

当然,你可以选择你想恢复哪个 stash,通过指定 stash id 来完成, 同样,pop 会移除堆栈中的指定 stash,而 apply 不会。

$ git stash pop stash@{2}
# 直接写 id 也可以
$ git stash pop 2

或:

$ git stash apply stash@{1}
# 直接写 id 也可以
$ git stash pop 1

清理 stash

当你不需要 stash 的时候,通过下面的命令来清理:

  • git stash clear 清理所有的 stash
  • git stash drop <stash_id> 删除指定的 stash
$ git stash drop 0

展示 stash 中的修改

使用 git stash show <stash_id> 来展示修改:

$ git stash show 0
 dao.py | 3 +++
 1 file changed, 3 insertions(+)

传入 --patch 或者 -p 查看更详细的信息:

diff --git a/dao.py b/dao.py
index e69de29..8941b16 100644
--- a/dao.py
+++ b/dao.py
@@ -0,0 +1,3 @@
+def addUser(user):
+    session.insert(user)
+    session.commit()

可见是添加了一个叫 addUser 的方法。

恢复 stash 到新的分支

有一个场景,当你想要恢复 stash 的时候,原分支上已经做了与你 stash 冲突的修改。这时候 pop stash,就会造成代码冲突,这时候就可以使用 git stash branch <new_branch_name stash_id> 命令来解决,它会创建一个新的分支,并把 stash pop 到新分支上,你可以在新分支上解决冲突与进一步修改:

$ git stash branch feature/modify-dao 0
Switched to a new branch 'feature/modify-dao'
On branch feature/modify-dao
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   dao.py

Dropped refs/stash@{0} (4a09ff22f71b41ea5426f16463e61eb9d491c840)

创建一个 stash 但先不存储

在有些场景下,你可能需要先创建一个 stash,但不想立刻保存到 stash 堆栈中。这时候可以使用 git stash create '<desc>' 命令完成,它创建一个 stash,并返回一个引用,在稍后需要存储到堆栈的时候,再使用 git stash store -m "<desc in stack>" "<引用id>" 命令。

# 为了方便先清理所有 stash
$ git stash clear
# 创建但不存储到堆栈
$ git stash create 'sample stash'
db37916f9a66853ed780174d305900a757f2cc0b
$ git stash list
# 空结果

实际存储:

git stash store -m "sample stash testing.." "db37916f9a66853ed780174d305900a757f2cc0b"

总结

本文介绍了 stash 的应用场景与常用用法,希望能有所帮助。

参考: opensource.com/article/21/…