头图

stash的字面意思:隐藏,储藏

当我们以多人协同工作的方式基于同一个github仓库进行开发时,免不了遇到多人同时在本机对同一文件进行编辑的情况出现。

看一个具体的场景,当我使用git pull时,收到错误提示:我本地修改了SandboxTest.java这个文件,而此时远端仓库里,已经有另一位同事从本地提交了对该文件的修改,而我俩对这个文件的编辑有冲突之处,因此提示我先“stash my local change”:

使用git stash,将我对该文件的修改暂存到stash区域:

此时我就可以顺利地执行git pull命令,先将我同事的最新代码从远端拖到本地。

然后执行git stash pop,将我自己本地的修改从stash区域取出来:

此时当然会有冲突出现,因为我们对同一文件做了修改,冲突的地方会显示在编辑器里,此时手动处理完这些冲突,重新提交即可。

git stash 命令是 Git 中用于临时保存当前工作目录的修改的一个非常强大的工具。这个命令会将未提交的工作内容保存到一个栈(stack)中,以便用户可以清空当前工作目录,然后稍后再恢复这些修改。对开发者来说,当需要切换分支或者拉取最新代码但又不希望丢失当前工作进度时,git stash 是一个非常有用的命令。

工作原理

git stash 命令会将当前工作目录和暂存区中的修改保存起来,并将其从工作目录中清除。保存的修改就像是一个堆栈中的对象,后进先出(LIFO)。每次执行 git stash,都会在栈顶保存当前的工作状态。

基本用法

最常见的 git stash 命令是 git stashgit stash pop

  • git stash: 将当前的暂存区和工作目录中的修改保存到栈中,并将这些修改从工作目录和暂存区中清除。
  • git stash pop: 恢复最近一次保存的修改,并从栈中移除这个保存的状态。

示例

让我们通过一些示例来展示 git stash 的基本用法和一些高级用法:

场景 1:保存当前工作进度

假设你正在工作中,对某些文件进行了修改,但突然需要切换到其他分支。此时,你不希望把当前的修改提交到版本控制中,但又不想丢失这些修改。你可以使用 git stash 来保存这些修改。

$ git status
On branch feature
Changes not staged for commit:
    modified:   file1.txt
    modified:   file2.txt

$ git stash
Saved working directory and index state WIP on feature: a1b2c3d Update README
HEAD is now at a1b2c3d Update README

$ git status
On branch feature
nothing to commit, working tree clean

此时,file1.txtfile2.txt 的修改已经被暂存并从工作目录中清除了。你可以自由地切换分支:

$ git checkout main
Switched to branch 'main'

当你完成其他工作后,可以回到原来的分支并恢复刚才的修改:

$ git checkout feature
Switched to branch 'feature'

$ git stash pop
On branch feature
Changes to be committed:
    modified:   file1.txt
    modified:   file2.txt
Dropped refs/stash@{0} (96b8c9e827e7f2c1e9ded2fe61eb9802f0ab3bab)

场景 2:查看已保存的修改列表

对于复杂的开发流程,你可能会多次使用 git stash 来保存不同阶段的修改。git stash list 命令可以查看当前栈中所有保存的修改。

$ git stash list
stash@{0}: WIP on feature: a1b2c3d Update README
stash@{1}: WIP on feature: e5f6g7h Fix bug in login
stash@{2}: WIP on main: i8j9k0l Add unit tests

场景 3:恢复指定的修改

如果你希望恢复特定的一次修改,可以使用 git stash apply 来应用特定的 stash 而不从栈中移除它。通过指定索引,可以恢复某次特定的修改。

$ git stash apply stash@{1}
On branch feature
Changes to be committed:
    modified:   login.js
    modified:   utils.js

这种方式可以保留原来的 stash,从而方便日后再次应用。

高级用法

git stash 命令有一些附加选项,可以处理更为复杂的场景。

  1. 仅保存未暂存的修改: 有时你可能只想保存工作目录中未暂存的修改,而不包含暂存区的修改。此时可以使用 git stash --keep-index

    $ git stash --keep-index

    这个命令将会把未暂存的修改保存到 stash,同时保留暂存区中的修改。

  2. 指定描述信息:为了更好地管理保存的修改,可以在 git stash 时添加描述信息,方便以后查找。

    $ git stash save "WIP: Working on user authentication"
  3. 管理多个 stash:尽管 git stash pop 会自动从栈中移除一次保存的状态,但有时候你可能希望保留这个状态。你可以使用 git stash apply 来应用而保留它。如果后来你确定不再需要这个保存的修改,可以使用 git stash drop 来删除。

    $ git stash drop stash@{0}
  4. 删除所有 stash:在完成所有工作后,你可能希望清空所有 stash。此时可以使用 git stash clear

    $ git stash clear

场景 4:合并冲突

在恢复 stash 时,可能会碰到合并冲突。这种情况下,Git 会提示并让你手动解决冲突。解决完冲突后,你可以继续使用 git add 来暂存解决冲突的文件,然后使用 git commit 来完成合并。

$ git stash pop
Auto-merging file1.txt
CONFLICT (content): Merge conflict in file1.txt
...

$ git status
On branch feature
You have unmerged paths.
...
Unmerged paths:
  (use "git add <file>..." to mark resolution)
    both modified:   file1.txt
...

$ vim file1.txt  # 手动解决冲突
$ git add file1.txt
$ git commit -m "Resolve merge conflict in file1.txt"

场景 5:Git 同 Github 的交互

在使用 git stash 命令时,可能很多人好奇它在客户端同 Github 交互的情景下表现如何。实际上,git stash 是一个纯本地操作的命令,它不会涉及到远程仓库的交互。这意味着,无论你如何使用 git stash,它都不会影响你的远程仓库。

例如,当你在本地执行 git stash 后,你可以继续进行其他的远程操作如 git fetch, git pull, git push 等等,这些操作都不会受 git stash 的任何影响。同样的,你可以在恢复 stash 之后继续对代码进行处理,然后再进行提交和推送。

$ git stash
$ git fetch origin main
$ git checkout main
$ git merge FETCH_HEAD
# 解决冲突或者进行其他操作
$ git push origin main
$ git checkout feature
$ git stash pop

这展示了如何在 stash 状态后继续进行远程仓库的操作,显示了 git stash 的灵活性和无缝集成能力。

详细说明

工作原理

Git 的设计核心是一个简单又高效的文件系统——Object Database,包含了 blobs,trees 和 commits 等对象。每次你运行 git stash 时,Git 实际上做了如下操作:

  1. 创建一个新的 commit 表示工作目录和暂存区的状态。
  2. 创建另一个 commit 表示暂存区的状态。
  3. 使用这些 commits 来创建一个新的 stash-entry。
  4. 将当前状态恢复到 HEAD(在 git stash 时,暂存区和工作目录会变为空)。

这种机制背后体现了 Git 的强大的 snapshot 容器和数据存储模型。不仅使得 git stash 的操作几乎瞬间完成,还确保整个操作是完全反向可追踪的。

保存未跟踪文件

git stash 默认不包括未跟踪的文件。如果你希望 stash 中包含这些未跟踪的文件,你需要使用 -u 选项。

$ touch newfile.txt
$ git status
On branch feature
Untracked files:
  (use "git add <file>..." to include in what will be committed)
    newfile.txt

$ git stash -u

在执行 git stash -u 后,newfile.txt 也会被暂存起来。

忽略遗漏的文件

有时你不想将忽略的文件(在 .gitignore 中定义的文件)包括在 stash 中。这时可以使用 git stash -a 来将这些文件也包括进去。

$ touch ignoredfile.txt
$ git status
On branch feature
Ignored files:
  (use "git add -f <file>..." to include in what will be committed)
    ignoredfile.txt

$ git stash -a

这样,ignoredfile.txt 也会被暂时保存起来。

检查 stash 中的内容

为了更加精确地管理存储的修改,可以使用 git stash show 以及 git stash show -p 命令来查看具体的差异。

$ git stash show
 file1.txt | 2 ++
 file2.txt | 4 ++--

$ git stash show -p
diff --git a/file1.txt b/file1.txt
index 83db48f..bf280ff 100644
--- a/file1.txt
+++ b/file1.txt
@@ -1,3 +1,5 @@
 ...
diff --git a/file2.txt b/file2.txt
index 83db48f..bf280ff 100644
--- a/file2.txt
+++ b/file2.txt
@@ -1,6 +1,8 @@
 ...

git stash show 会显示一个简要的差异信息,而 git stash show -p 则提供详细的文件差异内容。

总结

通过以上的详细阐述和示例,可以看到 git stash 是一个非常灵活和强大的工具,适用于各种开发场景下的临时保存和恢复工作进度。当我们需要在不同工作状态之间快速切换时,git stash 提供了无缝且高效的操作方式。

从基础用法到高级管理,再到与 Github 的交互,git stash 都表现出简洁和强大的一面。作为开发人员,熟练掌握这个命令可以极大提高工作效率,使你能够更加灵活地应对日常工作中的各种挑战。无论你是在处理短期的修复任务,还是在进行长期的功能开发,git stash 都是你不可或缺的得力工具。


注销
1k 声望1.6k 粉丝

invalid