我们开发过程中可能会遇到同一个项目有多个分支在并行开发, 在开发其中一个分支的时候, 另一个分支突然需要做点什么事情; 如果此时代码刚写了一半, 提交也不合适, 撤销也不舍得, 没有类似 git stash 的工具就显得很尴尬; git stash 正是用来解决此类问题的有效解决方案; git stash 灵活的堆栈风格及列表风格的命令, 让我们处理分支间并行跳跃式开发变得游刃有余;
查询操作
查看所有快照简要信息:1
git stash list
查看快照详情
仅查看改动的类及改动行数:1
2
3
4# 查看最新的快照
git stash show
# 查看第 n 个快照的信息
git stash show stash@{n}
查看具体的改动 diff:1
2
3
4# 查看最新的快照
git stash show -p
# 查看第 n 个快照的信息
git stash show -p stash@{n}
贮存操作
1 | # 不指定 message 直接贮存(默认使用 HEAD 的 commit id 与 commit message 作为 stash message) |
1 | # 使用指定 message 保存当前修改上下文 |
贮存部分更改内容
如果有的时候我们只是想贮存部分修改的文件, 而继续编辑剩下的文件, 可以按如下操作:1
2
3
4
5
6# 1. 先把不要贮存的改动加入索引
git add file_path
# 2. 使用 –-keep-index 选项将未加入 index 的改动贮存起来
git stash save –-keep-index "stash_message"
# 3. 撤销加入索引的改动
git reset HEAD .
这里使用了 –-keep-index 选项以避免 stash 暂存区的修改, 局限性是我们必须先将目标文件加入索引, stash 完成后再将其从索引中撤销, 增添了一些复杂性;
恢复操作
1 | # 使用最新的快照恢复, 并将其弹出存储堆栈 |
1 | # 使用最新的快照恢复, 但不将其弹出存储堆栈 |
丢弃操作
1 | # 删除最新的快照 |
使用的坑
git stash 虽然很灵活, 但是也有一些使用上的坑: git stash 不会保留贮存前的 git 状态, 恢复后统一变为工作区状态, 举两个例子:
- 如果我们对一批修改中的局部变更使用了 git add 加入了暂存区, 然后不加任何选项, 将所有修改全部 stash, 等后面再恢复的时候, 这些修改虽然在, 但是都将清一色变成
Changes not staged for commit
, 已经区分不出来哪些变更曾加过索引了; - 如果我们刚刚合并了一个分支, 冲突很大, 当我们挨个文件处理完冲突后, 此时的 git 状态应该是
All conflicts fixed but you are still merging
, 如果我们不及时提交此次合并的修改, 而将其 stash 起来, 等后面恢复的时候, 灾难就开始了:
被合并分支的修改以及解决冲突的修改确实都在, 但他们已不是 merging 状态, 而是工作区状态, 若此时再提交变更, 根本就没有合并分支, 而只是将另一个分支的修改复制到 base 分支上而已 (外加一些冲突处理);
当然这还不是最坑的地方, 如果此时想再重新合并目标分支, 会发现冲突会比第一次要多得多: 被合并分支修改的每一个文件, 都是整片整片的冲突, 因为我们把这些修改打包复制过来了, 等于两个分支都修改了相同的地方, 便造成了大面积冲突(讽刺的是, 仔细一看, 两边冲突的代码绝大部分还都是相同的); 一般到了这个地步, 我们就只能放弃了, 重新 reset 到上次合并之前的 commit, 重新再来吧;