场景

在同一个应用(代码)的情况下
1、产品发来一个新的需求,波波同学创建了一个分支A并进行功能开发。
2、系统出现一个 bug,波波同学需要停下开发工作,优先修复bug,于是他想创建一个新的分支B。
3、由于在分支A上已经开发了一部分功能,那么就需要先把分支A上的代码进行提交,然后创建分支B。此次分支A的提交基本上是一次无意义的提交。如果一直采用这种方式来创建新的分支,那么会在分支A上形成大量无用的提交记录,不利于代码的跟踪。
4、步骤3 的本质是将分支A修改的代码进行存档,对于分支B是透明的。那么有没有更好的方式存档代码呢?这便是本文的主题:git stash 神器。

有的人把 stash 称为【储藏】,我觉得称为【存档】更形象一些,玩过游戏的朋友应该更容易理解存档哈,文章中统一称为存档。大家怎么喜欢怎么来哈,如有不正之处,欢迎批评指正。

在介绍 stash 之前,我们先简单的介绍下 git 中的几类文件:

  • 添加到暂存区的修改(staged changes)
  • git 跟踪的但并未添加到暂存区的修改(unstaged changes)
  • 在工作目录中新的文件,git为跟踪的(untracked files)
  • 被忽略的文件(ignored files)

用法

存档当前的修改(git stash)

git stash 把所有未提交的修改都归档,包含暂存的和非暂存的文件。执行该命令后,当前的工作目录就 clean 了。

示例:

D:\workspace\buffalo>git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   readme.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:   readme.txt


D:\workspace\buffalo>git stash
Saved working directory and index state WIP on master: 28469b9 修改测试数据

D:\workspace\buffalo>git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

D:\workspace\buffalo>

需要说明的是,stash 是基于本地存储的,不会通过 git push 上传到 git server 上。
一般在进行存档时,我们需要为存档增加一些备注,记录版本变化内容,git stash 不允许我们输入备注的,但 git 为我们提供了另一个命令 git stash save "comment" 来解决这个问题。

示例:

D:\workspace\buffalo>git stash save "add file readme.txt"
Saved working directory and index state On master: add file readme.txt

D:\workspace\buffalo>

查看现有的存档(git stash list)

通过 git stash list 命令可以查看当前工程的现有存档。

示例:

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file readme.txt

D:\workspace\buffalo>

通过示例我们可以看到,存档名为:stash@{0},存档发生在 master 分支,存档时的备注为 “add file readme.txt”。
存档名是一个文字序列,类似stash@{0}、stash@{1}、stash@{2}、stash@{3}等等。

恢复已存档的修改(git stash pop|apply)

通过 git stash pop|apply 命令可以将存档恢复至当前工程。popapply 的区别在与,在恢复归档后 pop,会将存档删除,而 apply 则不会删除存档。

git stash pop|apply 命令恢复第一个存档,等价于 git stash pop|apply stash@{0}
git stash pop|apply stash_name 命令恢复指定存档名的存档。

示例:

D:\workspace\buffalo>git stash save "add file readme.txt"
Saved working directory and index state On master: add file readme.txt

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file readme.txt

D:\workspace\buffalo>git stash save "add file init.txt"
Saved working directory and index state On master: add file init.txt

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file init.txt
stash@{1}: On master: add file readme.txt

D:\workspace\buffalo>git stash apply stash@{1}
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   readme.txt


D:\workspace\buffalo>git stash list
stash@{0}: On master: add file init.txt
stash@{1}: On master: add file readme.txt

D:\workspace\buffalo>

通过示例可以发现,我们使用 git stash apply stash@{1} 命令将第二个存档恢复,并且没有删除该存档。

移除存档(git stash drop|clear)

git stash drop stash_name 命令删除指定存档名的存档。
git stash clear 命令删除当前工程的所有的存档。

示例:

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file init.txt
stash@{1}: On master: add file readme.txt

D:\workspace\buffalo>git stash drop stash@{1}
Dropped stash@{1} (616728a7d8964ee86c1c77b19b906848cfe1cde0)

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file init.txt

D:\workspace\buffalo>

通过示例可以发现,我们使用 git stash drop stash@{1} 删除了第二个存档。

查看存档的DIFF(git stash show)

git stash show 命令查看第一个存档的DIFF,等价于 git stash show stash@{0}
git stash show stash_name 命令查看指定存档的DIFF。

示例:

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file readme.txt
stash@{1}: On master: add file init.txt

D:\workspace\buffalo>git stash show
 readme.txt | 1 +
 1 file changed, 1 insertion(+)
 
D:\workspace\buffalo>git stash show stash@{1}
 init.txt | 1 +
 1 file changed, 1 insertion(+)

D:\workspace\buffalo>

基于存档创建分支(git stash branch)

git stash branch branch_name 命令基于第一个存档创建分支。
git stash branch branch_name stash_name 命令基于指定的存档创建分支。

示例:

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file readme.txt
stash@{1}: On master: add file init.txt

D:\workspace\buffalo>git stash show stash@{1}
 init.txt | 1 +
 1 file changed, 1 insertion(+)

D:\workspace\buffalo>git stash list
stash@{0}: On master: add file readme.txt
stash@{1}: On master: add file init.txt

D:\workspace\buffalo>git stash branch test-stash
Switched to a new branch 'test-stash'
On branch test-stash
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        new file:   readme.txt

Dropped refs/stash@{0} (b7afb7e9eafe241d318a22693e0b0fcd1bccde08)

通过示例可以发现,我们使用 git stash branch test-stash 基于第一个存档创建了 test-stash 分支。

存档未跟踪和忽略的文件(git stash -u|a)

git stash -ugit stash --include-untracked 命令可以存档未跟踪的文件。
git stash -agit stash -all 命令可以存档所有的文件。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐