【问题标题】:git selective revert local changes from a filegit 选择性恢复文件中的本地更改
【发布时间】:2009-07-10 11:40:05
【问题描述】:

在我跟踪 svn 存储库的 git 存储库中,我对单个文件进行了多次编辑。

现在我想恢复这些更改(如 svn revert),但只恢复文件的一部分。

我希望能够查看文件上的差异,丢弃(还原)我不想要的更改并保留我想要的更改。

git add -i 

command 似乎可以选择执行此操作,但我还不想进行此操作。

【问题讨论】:

    标签: git version-control git-svn


    【解决方案1】:

    我相信您可以最简单地做到这一点:

    git checkout -p <optional filename(s)>
    

    来自手册页:

       −p, −−patch
           Interactively select hunks in the difference between the <tree−ish>
           (or the index, if unspecified) and the working tree. The chosen
           hunks are then applied in reverse to the working tree (and if a
           <tree−ish> was specified, the index).
    
           This means that you can use git checkout −p to selectively discard
           edits from your current working tree.
    

    【讨论】:

    • 另外,如果您不想选择性地执行此操作,您可以使用“git checkout -- ...”来放弃更改。
    • 它处理目录吗?
    • 在放弃更改时,这对我来说似乎失败了很多(“错误:补丁失败 ”,“错误:补丁不适用”)。奇怪的是,当在补丁模式下使用a 选项丢弃整个文件时,我会收到这些错误,但git checkout -- &lt;file&gt; 按预期工作。有人知道为什么吗?
    • 如果文件已经打过补丁,我会遇到几次该错误,因此交互式补丁与当前文件应用的补丁已过期。如果我不小心丢弃了两次大块,则在使用源树之类的 gui 工具时会发生这种情况。第二次会产生这个错误。
    【解决方案2】:

    您可以直接使用git checkout -p 执行此操作。请参阅下面的Daniel Stutzbach's answer


    旧答案(在引入checkout -p 之前):

    你可以这样做:

    git add -i
    

    (选择你想保留的帅哥)

    git commit -m "tmp"
    

    现在您有了一个只包含您想要保留的更改的提交,其余部分未暂存。

    git reset --hard HEAD
    

    此时,未提交的更改已被丢弃,因此您拥有一个干净的工作目录,其中包含您想要保持提交的更改。

    git reset --mixed HEAD^
    

    这会删除最后一次提交 ('tmp'),但会将修改保留在您的工作目录中,未暂存。

    编辑:将--soft 替换为--mixed,以清理暂存区。

    【讨论】:

    • 这将提交我想要保留的更改,不是吗?我还不想提交这些更改。毫米也许我把提交太认真了。也许我现在应该放松一下,因为它都在本地回购中。顺便说一句 git reset --soft HEAD^ 做什么?
    • "git reset --soft HEAD^" 从某种意义上撤消提交,它保持工作目录和索引不变,并将当前分支移回一个提交。
    • 谢谢雅库布。 Paolo 为什么这里需要对 head - 1 进行软重置?部分提交和硬重置应该足以保留一些更改并丢弃其他更改?
    • 丹尼尔在下面的回答很简单,看起来是正确的做法。
    【解决方案3】:

    您可以在文件上运行git diff,保存生成的差异,编辑它以删除您想要保存的更改,然后通过patch -R 运行它以撤消剩余的差异。

    git diff file.txt >patch.tmp
    # 编辑 patch.tmp 删除你想要保留的块
    补丁 -R 

    【讨论】:

    • 我的补丁文件中有 2 个块并删除了一个。不知道是什么原因,但补丁 -R 一直被拒绝。
    • 您在另一条评论中提到git diff 显示整个文件已更改。当您使用与以前不同的行结尾保存文件时,通常会发生这种情况。这也会导致patch 拒绝补丁文件。这听起来像是发生了什么吗?
    • 你是对的。每当我使用 patch 命令时,行尾都会被切换。我在 Windows 上并使用 cream/vim。我认为需要先解决这个问题。
    • 我无法解决 Windows 上的补丁问题。虽然我确信这行得通,但我更喜欢使用 Paolo 的食谱。为了喜欢那些使用 git add -i 处理差异的交互式命令。
    【解决方案4】:

    看起来像你想要的

     git revert --no-commit $REVSISON 
    

    然后你可以使用

     git diff --cached
    

    在提交之前查看将进行哪些更改(因为还原只是向前方向的提交,它复制了过去更改的逆向)

    如果您使用的是纯 Git 存储库,则可以根据您的目标,利用交互式 rebase (git rebase -i) 回到您不喜欢的提交并追溯编辑提交,以便您所做的更改不喜欢从未发生过,但这通常只是因为如果你知道你就再也不想看到它了。

    【讨论】:

    • 我确实按照你提到的那样恢复到以前的版本(对吗?),现在 git diff 只显示整个文件已更改。它应该显示我所做的编辑?
    【解决方案5】:

    重新阅读该问题,听起来您想恢复工作树中的更改,而不是先前提交的更改,但其他一些答案听起来像是我的阅读可能是错误的。你能澄清一下吗?

    如果更改只是在您的工作副本中,那么最简单的方法是暂存您想要保留的更改:

    git add -i <file>
    

    然后通过查看索引版本丢弃您不想保留的更改:

    git checkout -- <file>
    

    如果您还不想暂存更改,请取消暂存更改:

    git reset -- <file>
    

    此配方仅恢复对文件(或您指定的文件)的选定更改,不会创建任何需要恢复的临时提交。

    如果您只想选择性地应用之前提交中所做的一些更改,那么您可以先将文件重置为之前提交的状态:

    git reset <commit_before_first_unwanted_change> -- <file>
    

    然后您可以按照之前的方法 git add -i &lt;file&gt; 暂存您想要保留的更改,git checkout -- &lt;file&gt; 丢弃不需要的更改,git reset -- &lt;file&gt; 来“取消暂存”这些更改。

    【讨论】:

      【解决方案6】:

      当文件位于我通过 ssh 终端访问的服务器上时,此处答案中描述的命令行选项很方便。 但是,当文件在我的本地机器上时,我更喜欢以下方式:

      在 netbeans 编辑器(带有 git 支持)中打开文件。 Netbeans 在行号处放置红色/绿色/蓝色标记,以指示删除/添加/修改内容的位置(分别)。

      右键单击这些标记中的任何一个,您都可以选择撤消该更改。 此外,您可以右键单击红色和蓝色标记以在弹出窗口中查看旧版本。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-05
        • 1970-01-01
        • 1970-01-01
        • 2016-01-28
        • 2017-12-29
        • 2011-06-22
        • 2017-05-28
        相关资源
        最近更新 更多