1. Git 暂存(Staging)
在 Git 的三大工作区域中,我们主要在工作区(Working Tree)中进行修改操作,例如:
$ echo more >> file1
$ cat <<EOI >file2
> new
> EOI
$ rm file3
执行完这些操作后,可以使用 git status
查看当前状态:
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: file1
deleted: file3
Untracked files:
(use "git add <file>..." to include in what will be committed)
file2
no changes added to commit (use "git add" and/or "git commit -a")
此时,我们看到的是“未暂存”的修改。我们可以选择是否将这些文件的修改加入暂存区(Staging Area):
$ git add file1
$ git add file2
此时,我们并没有暂存 file3
的删除操作,但将 file1
和 file2
的新内容加入了暂存区。当然,我们仍然可以继续添加或撤销暂存。
确认无误后,再次查看状态:
$ git status
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: file1
new file: file2
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: file3
此时,Changes to be committed
下显示的是已暂存的内容。
当我们执行 git commit
后,Git 会将这些暂存内容提交为一个新的提交节点,并更新当前分支的指针。
2. Git 的“中间状态”问题
有时候,我们可能还没有完成当前的修改,但需要切换分支去做其他事情。比如:
$ git checkout branch1
error: Your local changes to the following files would be overwritten by checkout:
file1
Please commit your changes or stash them before you switch branches.
Aborting
虽然 Git 不需要动 file3
或 file2
,但 file1
的当前状态与暂存或未暂存版本有冲突,Git 会阻止切换分支以防止数据丢失。
这是因为 Git 的暂存区和工作区是全局的,不与分支绑定。一旦切换分支,这些修改可能会被覆盖或丢失。
3. Git 储藏(Stash)
Git 提供了一个非常实用的功能:git stash
,它允许我们保存当前的工作状态,而不必提交。之后可以随时恢复这些修改。
3.1. 准备环境
假设我们当前工作区是干净的:
$ git status
On branch master
nothing to commit, working tree clean
现在我们做一些修改:
$ touch untrackedfile
$ echo $(date) >> trackedfile
$ rm deletedfile
查看状态:
$ git status
On branch master
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted: deletedfile
modified: trackedfile
Untracked files:
(use "git add <file>..." to include in what will be committed)
untrackedfile
no changes added to commit (use "git add" and/or "git commit -a")
如果我们想暂时放下当前工作,去处理其他任务,可以使用 git stash
。
3.2. 创建储藏
$ git stash
Saved working directory and index state WIP on master: 3fa666d last commit message
此时再次查看状态:
$ git status
On branch master
Untracked files:
(use "git add <file>..." to include in what will be committed)
untrackedfile
nothing added to commit but untracked files present (use "git add" to track)
可以看到,只有未跟踪的文件 untrackedfile
还在,其他修改都被储藏了。
3.3. 储藏未跟踪文件
默认情况下,git stash
不会保存未跟踪的文件。如果需要包含它们,使用 --include-untracked
(或 -u
):
$ git stash --include-untracked
Saved working directory and index state WIP on master: 3fa666d last commit message
$ git status
On branch master
nothing to commit, working tree clean
也可以使用 --all
(或 -a
),它还会包括被 .gitignore
忽略的文件。
3.4. 查看储藏列表
Git 的 stash 是一个栈结构,可以用 git stash list
查看:
$ git stash list
stash@{0}: WIP on master: 3fa666d last commit message
stash@{1}: WIP on master: 3fa666d last commit message
每个 stash 有一个编号,可以用于后续操作。
也可以使用 git log
看 stash 的提交结构:
$ git log --all --decorate --oneline --graph
*-. 46b69d2 (refs/stash) WIP on master: 3fa666d last commit message
|\ \
| | * 6def6bf untracked files on master: 3fa666d last commit message
| * 53095b4 index on master: 3fa666d last commit message
|/
[...]
3.5. 查看储藏内容
使用 git stash show
查看某个 stash 的修改:
$ git stash show 1
$ git stash show 0
deletedfile | 0
trackedfile | 1 +
2 files changed, 1 insertion(+)
如果想查看未跟踪文件的修改,加上 --include-untracked
:
$ git stash show --include-untracked 1
untrackedfile | 0
1 file changed, 0 insertions(+), 0 deletions(-)
3.6. 恢复与删除储藏
主要有三种操作:
apply
:将 stash 的修改应用到当前工作区pop
:先apply
,然后drop
掉该 stashdrop
:删除某个 stash
使用方法:
$ git stash apply stash@{1}
$ git stash pop stash@{0}
$ git stash drop stash@{1}
⚠️ 注意:pop
操作会删除 stash,但如果当前工作区有冲突,它不会删除 stash。
3.7. 高级用法
git stash create
:创建一个 stash 但不加入 stash 栈,返回其 commit hash:
$ git stash create
087d502f375249eb1306660cea5822aa5e79d78d
git stash store
:将一个 hash 加入 stash 栈:
$ git stash store -m "custom message" 087d502
git stash branch
:从某个 stash 创建一个新分支并切换过去:
$ git stash branch new-branch stash@{1}
4. 总结
✅ Git 的暂存机制是日常开发中最常用的功能,用于有选择地提交修改。
✅ 当我们需要临时切换分支或保存未完成的修改时,git stash
是非常实用的工具。
✅ 要注意默认情况下 stash
不包含未跟踪文件,如需保存,需加 --include-untracked
。
✅ stash 是一个栈结构,支持查看、恢复、删除等操作,也可以用于创建新分支。
✅ 在脚本中使用 create
和 store
可以更灵活地管理 stash。
在实际开发中,掌握好 Git 的 staging 和 stash 操作,可以显著提升开发效率和代码管理能力。