■ space · 散文道
git stash push -m "why" -- <path> 只寄停指名的文件;其余脏文件一动不动。
从任何 stash 取回单个文件: git restore --source stash@{0} -- <path> ——条目原封不动。
pathspec 形式自 git 2.13(2017 年 5 月);未跟踪文件需要 -u。
劈开
三个脏文件,一个必须走。看这棵树劈成两半 —— 一个文件进 stash,两个不动:
之前 · git status --short
M app.conf ← must move
M notes.md
M main.py
之后
M notes.md ← never moved
M main.py ← never moved
stash@{0}: On main: app.conf prod tweak
app.conf 回到它已提交的状态,坐在 stash@{0} 里——一旦 git stash list 不止一条,-m 消息那三秒钟就值回票价;「WIP」这类的名字老得很快
pathspec 就是全部戏法
光杆 git stash 扫走整棵工作树 —— 所有被跟踪的修改全进去,一切回到 HEAD。脏树是 混合态:一个文件可以交了,其余真没写完。两个值得知道的细节:
- pathspec 放在
--后面。 双杠之后全是路径,不是旗标 —— 跟git checkout -- <path>同一惯例,而且不是摆设:老版本 git 会读错裸路径。 - 未跟踪文件需要
-u。 新生文件没有被跟踪的历史可 stash,所以光杆push会跳过它。git stash push -u -- newfile.py会带上它;-a更进一步,连被忽略的文件也一起扫。
半个文件:交互式劈开
当文件本身半生不熟 —— 三个好的 hunk、一个见不得人的 —— git stash -p(或 git stash push -p)会逐个 hunk 走过去,问你 Stash this hunk [y,n,q,a,d,j,g,/,e,p,?]?。是该进 stash 的 hunk 就答 y,该留下的答 n;结果是一个只装着你批准内容的 stash。同一套逐 hunk 机器也开着 git add -p,反射弧可以直接搬用。两种粒度,并排放:
git stash push -- <path> | git stash -p | |
|---|---|---|
| 粒度 | 整个文件 | 单个 hunk |
| 速度 | 一条命令,可脚本化 | 交互式,逐 hunk |
| CI 里可重复 | 可以(路径当参数) | 不行 —— 提示符前得有人 |
| 最适合 | 「这个文件,其他不要」 | 「这个改动,那个不要」 |
| 起步于 | git 2.13(2017 年 5 月) | 很早就可用 |
顺着文档自己的模型给个拇指法则: 边界是文件就用 pathspec, -p 边界在文件里面就用它。
取回一个文件
git stash pop 会恢复 stash@{0} 并删掉条目 —— 常规路,但 pop 对整个 stash 要么全成要么全不动,冲突会把 pop 掐断、条目保留。两条更细的路:
# 1. apply without dropping (safe re-run)
git stash apply stash@{0}
# 2. pull ONE file out of a stash, leave the entry intact
git restore --source stash@{0} -- app.conf
# pre-2.23 spelling of the same operation:
git checkout stash@{0} -- app.conf
验证:restore 之后 git stash list → stash@{0} 还站着 —— 只有 pop 会删条目
什么时候 stash 是错的工具
stash 是草稿纸,不是分支。 stash 只住在你机器上,除一行之外不带任何说明,而且出了名的容易忘 —— git stash list 考古学自成一门流派。git switch -c wip-labels 要过夜、要在机器间旅行、要带真正 commit message 的工作,属于分支:
单个文件到此为止 · 没有任何 fetch · 全程本地