【问题标题】:Undo part of unstaged changes in git撤消 git 中的部分未分级更改
【发布时间】:2010-12-31 05:02:21
【问题描述】:

如何在 git 中撤消部分未暂存的更改,但将其余部分保持为未暂存状态?我想出的办法是:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

这可行,但如果有类似git commit --interactive 的东西仅用于恢复更改,那就太好了。还有更好的方法吗?

【问题讨论】:

    标签: git


    【解决方案1】:

    您可以使用git checkout 并为其命名您要撤消的部分的名称。

    【讨论】:

      【解决方案2】:

      怎么样

      1. 使用索引中的更改退出受影响的文件
      2. 使用git add -p 仅将您想要的更改添加回索引。

      【讨论】:

        【解决方案3】:

        你可以的

        git checkout master -- path/to/file
        

        对于您要重置的每个文件。

        【讨论】:

        • 如果在分支上工作,或者使用 HEAD 代替 master。正如它在“git status”报告中所说(至少在最近的版本中)。
        【解决方案4】:

        您可以使用git checkout -p,它可以让您从工作副本和索引之间的差异中选择单独的块来恢复。同样,git add -p 允许您选择要添加到索引的块,git reset -p 允许您从索引和 HEAD 之间的差异中选择单个块以退出索引。

        $ git checkout -p file/to/partially/revert
        # or ...
        $ git checkout -p .
        

        如果您希望事先为您的 git 存储库创建快照以在还原这些更改之前保留这些更改,我喜欢这样做:

        $ git stash; git stash apply
        

        如果你经常使用它,你可能想给它起别名:

        [alias]
            checkpoint = !git stash; git stash apply
        

        如果您使用良好的编辑器模式或插件,恢复单个块或行会更容易,它可以支持直接选择要恢复的行,因为 -p 有时使用起来有点笨拙。我使用Magit,这是一种对使用 Git 非常有帮助的 Emacs 模式。在 Magit 中,您可以运行 magit-status,找到要还原的更改的差异,选择要还原的行(或者,如果您想在一次而不是一行),然后按k 恢复那些特定的行。如果你使用 Emacs,我强烈推荐 Magit。

        【讨论】:

        • 我认为这与我最初提出的解决方案一样复杂,但我认为我最初的解决方案具有将删除的行保存 30 天的好处,因为它们已提交。不过,我在想,围绕它编写一个 shell 脚本可能会很好。
        • 抱歉,我刚刚意识到 git checkout 也有一个 -p 标志,它完全符合您在单个命令中的要求。为之前的复杂步骤道歉;你可以使用git checkout -p。就保存东西而言,在做一些可能具有破坏性的事情之前,我经常做一个git stash; git stash apply(或创建一个别名为git checkpoint或其他东西)来将当前树记录在一个藏匿处,这样我就可以回到它,如果出了点问题。
        • 好了,这就是解决方案!至于别名,我认为像git commit -a -m "Backup Commit" --edit; git reset HEAD^ 这样的东西会更好,因为这样它就不会弄脏我的存储状态,我可能会用它来做其他事情。然后,只要您拥有 SHA1,您就可以在接下来的 30 天内挑选它。 --edit 允许您将信息添加到提交消息中,以帮助您稍后在需要时找到 SHA1。另一方面,这会弄脏 git reflog,所以我想这是基于你所做的权衡。
        • 检查点别名对我不起作用:只执行第一个命令,而不执行第二个命令。这很可悲,因为我会喜欢它。我正在使用 git 版本 1.7.10.4。
        • 有没有办法让git checkout -p 不将补丁应用到索引而只暂存它们?
        【解决方案5】:

        当我运行“git status”时,它会说:

        $ git status
        # On branch fr/fr.002
        # Changed but not updated:
        #   (use "git add <file>..." to update what will be committed)
        #   (use "git checkout -- <file>..." to discard changes in working directory)
        #
        #   modified:   makefile
        #
        no changes added to commit (use "git add" and/or "git commit -a")
        $
        

        所以,要取消未暂存的编辑,它会告诉我运行:

        git checkout -- makefile
        

        【讨论】:

        • 我认为他想知道如何还原单个大块,而不是一次还原整个文件。如果您只需要撤消文件中的所有更改,这当然是一种解决方案。
        • 是的 - 我怀疑你是对的。 'git checkout -p' 和 'git add -p' 选项似乎是想要的 - 正如你所说。
        【解决方案6】:
        git diff > patchfile
        

        然后编辑补丁文件并删除不想撤消的部分,然后:

        patch -R < patchfile
        

        【讨论】:

        • 然而,这个答案的简单性和易用性尤其令人钦佩。 +1
        • 生成的 patchfile 在 vi​​m 中看起来很棒,真的很有帮助!
        • 完美。可以确认它也可以在带有 Cygwin 和 Ubuntu bash for windows 的 Windows 下运行。
        • 注意你也可以使用git apply -R而不是patch(只是为了留在git的领域,或者在patch不可用的情况下)
        • patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
        【解决方案7】:

        Brian Campbell's answer 使我的 git 版本 1.9.2.msysgit.0 崩溃,原因未知,所以我的方法是暂存我想要保留的块,丢弃工作副本中的更改,然后取消暂存。

        $ git add -p
           ... select the hunks to keep
        $ git checkout -- .
        $ git reset HEAD .
        

        【讨论】:

        • 还有git stash -p。你可以做git stash -p; git reset --hard; git stash pop。这实际上与您正在执行的操作相同,只是您不必编写提交消息。
        • @asmeurer 欢呼。我的不需要提交消息,但使用 stash 确实比使用索引更有意义。
        猜你喜欢
        • 2013-03-11
        • 2016-03-07
        • 2021-09-30
        • 1970-01-01
        • 2017-08-06
        • 2016-12-07
        • 2015-01-30
        • 2021-02-17
        • 2018-11-01
        相关资源
        最近更新 更多