你如何只存储已添加的文件?

How do you stash only files that have been added?

例如,git status 给出以下内容:

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

    modified:   app/src/[....]
    modified:   app/src/[....]
    new file:   app/src/[....]
    deleted:    app/src/[....]
    modified:   app/src/[....]
    modified:   test/unit/[....]
    modified:   test/unit/[....]
    new file:   test/unit/[....]
    deleted:    test/unit/[....]
    modified:   test/unit/[....]

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:   test/unit/[....]

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    app/src/[....]/
    app/src/[....]/
    app/src/[....]/

(我把文件名都删掉了)

我如何只存储我 git add 编辑的更改(即 "Changes to be committed",而不是未暂存的更改或未跟踪的文件)以便我可以将它们转移到另一个分支?

提交这些文件,然后对提交进行变基。

Git 的基本存储机制是“提交”——事实上,git stash 所做的只是进行一些不寻常的提交——所以 是正确的.不过,它也许可以使用一些扩展,并且有更简单(嗯,可能更简单)的方法。

我不是 git stash 的忠实粉丝,但如果您习惯使用它,这里是其他方法中最简单的方法:

  1. git stash save(又名 git stash)。这将写入两个提交,一个基于当前索引,另一个用于保存尚未暂存的工作树文件。 (如果你需要保留 untracked 文件,你可以添加 -u 标志,然后存储脚本添加第三次提交。通常你可以让这些未跟踪文件浮动尽管在你的工作树中没有被跟踪。)这些提交不在任何分支上,它们只是 on/in 特殊的“隐藏”参考。与此同时,您仍在“错误的”分支上,我将在下面称之为 wrongbr

  2. git checkout 你想要的分支。现在你在正确的分支上。

  3. git stash apply --index。这使用了在步骤 1 中进行的特殊存储提交,同时也将它们留在存储中 (apply)。 --index 非常重要:它告诉存储脚本 将索引文件和未暂存文件分开 ,即返回您之前的已暂存和未暂存设置。

    如果一切顺利,您现在可以 git commit 对您希望的分支进行更改。先前暂存的文件再次暂存,未暂存的文件仍未暂存,因为您 apply-ed 存储了 --index。提交将提交已暂存的文件,而未暂存的文件未暂存。

  4. 现在你可以回到另一个“错误的”分支(你最初进行存储的地方)和 git stash applygit stash pop 有或没有 --index .您可能需要清除所有未暂存的文件(这样做是安全的,它们仍在隐藏中):git reset --hard,然后是 git checkout wrongbr,然后是 git stash pop。请注意 pop 只是 apply 后跟 drop:我们不 想要 删除 stash 在第 3 步中(stash 具有原始修改但未暂存文件的唯一副本),这就是我们在那里使用 apply 的原因,但现在我们(大概)do 想删除藏匿处,所以使用 pop 就可以了。

不过,第 3 步中存在一个很大的潜在陷阱:存储可能无法正确应用。如果是这样,您必须使用其他方法。这是我不太喜欢 stash 系统的原因之一:它在棘手的情况下会崩溃,如果你不使用 stash,你就需要知道可以使用的工具。在这种情况下,您可以大部分时间只使用这些工具……然后在您确定它会起作用的情况下使用 stash 作为方便的快捷方式。


背景:一个提交现在获取索引中的任何内容——git ls-files --cached 将显示完整的内容,而 git status 将其缩减为“有趣”的内容并添加额外的有用信息——并且使用所有必要的树对象等对它们进行提交。新提交的父提交是当前提交之前的任何内容。

您希望在另一个分支上进行新提交。一种方法是现在就在当前分支上创建它;然后将该提交复制到不同分支上的新的不同提交。要执行“将提交复制到不同分支上的新的不同提交”,您可以使用 git cherry-pick。确实可以使用 git rebase:在幕后,它使用 git cherry-pick 本身。但是 rebase 并不是一个合适的工具:它是为集体挑选而设计的,而你只有一个提交;最后它使用 git reset 移动分支标签,但不是您想要的方式。你可以让它工作,但还有一些更合适的工具。

让我们回到最初的问题:您想获取当前索引并使用它进行新提交,但是 在另一个分支上 。如果您现在可以切换到另一个分支,不做任何其他事情,然后进行新的提交,这将是最简单的。

很有可能您可以做到这一点。只需 git checkout otherbranch,然后 git commit。这里有三种可能的情况:

  1. 另一个分支还不存在。伟大的!使用 git checkout -b newbranch 创建它,从您现在所在的位置开始。然后git commit。你已经完成了,除非你想将新分支重新设置为从“你现在所在的位置”以外的某个地方开始。如果是这样,请在新分支上使用 git rebase。请注意,在处理完未暂存的文件后,您可以稍后再进行变基。

  2. 另一个分支确实存在,而且——幸运的是——git checkout otherbranch工作正常。这样做并提交,你就完成了。然后,您可以 git checkout 未暂存文件所需的任何分支。

  3. 最烦人的情况:另一个分支确实存在,但是git checkout告诉你你将覆盖你没有提交的东西。

情况 3 是您需要提交或隐藏的情况。

在这里做什么取决于您最擅长的事情。例如,您可以尝试将上述四步 stash 方法作为最简单的替代方法。

不过,对于我自己来说,我现在就在“错误的”分支上提交,然后再次提交(或使用 git stash)以清除未暂存的文件。这给了我一个提交,我可以 git cherry-pick 进入 right 分支。这是一个可能有效的示例序列:

  1. git commit 进行提交,但是在“错误的”分支上(让我们调用您当前的分支 wrongbr 以供下面参考)。
  2. git stash save 保存未暂存的更改(或者,使用 -u,也保存未跟踪的文件)。
  3. git checkout 您希望提交所在的分支,例如 git checkout rightbr.
  4. git cherry-pick wrongbr。如果成功,那很好;如果不是,请根据需要编辑文件以在合并问题后清理,然后 git commit 结果。
  5. git checkout wrongbr:我们现在将通过删除在第 4 步中复制的提交来解决此问题。
  6. git reset --hard HEAD^:这会删除我们复制的提交。
  7. git stash pop(或做同样事情的 git stash apply && git stash dropapply 变体只是让您有机会在 drop 隐藏之前检查结果)。

注意这里的第 4 步:git cherry-pick 采用命名提交(wrongbr 的提示,其中包含我们想要的提交,它只是在错误的分支上),将它与其父 进行比较,然后尝试将结果差异应用到当前分支。如果当前分支中的文件与其在 wrongbr 中的相应文件有很大不同,这可能需要进行 3 向合并。这与在最初检查 rightbr 并提交的简单情况下出现复杂情况的地方相同。也就是说,我们正在做这个长版本,因为“最烦人”的情况发生在我们试图在提交之前只 git checkout rightbr 时,所以我们很有可能需要做一些修复。这也可能导致原来的4步stash方法出现问题。

  1. 存储所有内容,但保留索引(此存储将暂存(来自 git add)和非暂存编辑):

    git stash --keep-index

  2. Stash the index,也就是第1步stash之后剩下的所有内容(这就是你要stash的)

    git stash

  3. 弹出或应用(更安全)包含所有内容的存储,第 1 步中的那个(现在在 stash@{1} 中,因为最新的总是 stash@{0})。

    git stash apply stash@{1}

  4. 恢复最初添加到索引的文件,即 stash@{0} 中的文件,方法是从 HEAD

    中检出它们

    git checkout HEAD ./path/to/files/to/reset ./another/path/to/other/file/to/reset

  5. 如果您在第 4 步中搞砸了,请尝试 git reset HEAD --hard 清除所有本地更改并从第 3 步重新开始。