【问题标题】:How do you stash only files that have been added?您如何仅存储已添加的文件?
【发布时间】:2015-08-02 07:20:05
【问题描述】:

例如,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 added 所做的更改(即“要提交的更改”,而不是未暂存的更改或未跟踪的文件),以便我可以将它们转移到另一个分支?

【问题讨论】:

标签: git git-stash


【解决方案1】:

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

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

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

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

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

    如果一切顺利,您现在可以git commit 对您想要的分支进行更改。先前暂存的文件再次暂存,而未暂存的文件仍处于未暂存状态,因为您 apply- 使用 --index 编辑了暂存文件。提交将提交暂存文件,使未暂存文件不暂存。

  4. 现在您可以返回另一个“错误”分支(您最初在其中进行存储)和git stash applygit stash pop,无论是否使用--index。您可能需要清除所有未暂存的文件(这样做是安全的,它们仍在存储中):git reset --hard,然后是 git checkout wrongbr,然后是 git stash pop。请注意,pop 只是 apply 后跟 drop:我们不想要删除步骤 3 中的存储(存储只有原始修改但未暂存的文件),这就是我们在那里使用 apply 的原因,但现在我们(大概)确实想要删除存储,所以使用 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 &amp;&amp; git stash drop 做同样的事情,apply 变体只是让您有机会在 drop 存储之前检查结果)。

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

【讨论】:

  • 被评为更好的解释和完整的答案。
  • 这应该是那些投票数量众多的答案之一。我不知道为什么不是。
【解决方案2】:

提交这些文件,然后重新设置提交。

【讨论】:

    【解决方案3】:
    1. 存储所有内容,但保留索引(此存储将分阶段(来自git add)和非分阶段编辑):

      git stash --keep-index

    2. 存储索引,这是在步骤 1 中存储之后剩下的所有内容(这是您想要存储的内容)。

      git stash

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

      git stash apply stash@{1}

    4. 通过从HEAD 检出文件来恢复最初添加到索引中的文件,即stash@{0} 中的文件

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

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

    【讨论】:

      猜你喜欢
      • 2011-07-07
      • 2021-12-02
      • 2014-10-04
      • 2010-11-27
      • 1970-01-01
      • 2020-05-23
      • 2013-06-02
      • 2017-01-21
      • 1970-01-01
      相关资源
      最近更新 更多