git selection从文件还原本地更改


149

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

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

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

git add -i 

命令似乎可以选择执行此操作,但是我还不想上演此操作。

Answers:


91

您可以直接使用进行操作git checkout -p。请参阅下面的Daniel Stutzbach的答案


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

您可以这样做:

git add -i

(选择要保留的块)

git commit -m "tmp"

现在,您只提交了要保留的更改,其余的则撤消了。

git reset --hard HEAD

此时,未提交的更改已被丢弃,因此您拥有一个干净的工作目录,并且要保留在顶部的更改。

git reset --mixed HEAD^

这会删除上一次提交('tmp'),但会将修改保留在您的工作目录中,且不会进行暂存。

编辑:替换--soft--mixed,以清理临时区域。


这将提交我要保留的更改,不是吗?我还不想提交这些更改。嗯,也许我太认真了。也许我现在应该放松一下,因为这一切都在本地回购中。顺便说一句git reset --soft HEAD ^有什么作用?
Pradeep

“ git reset --soft HEAD ^”在某种意义上撤消了一次提交,即它保持工作目录和索引不变,并将当前分支一次提交移回。
2009年

谢谢雅库布。Paolo为什么在这里需要软复位到头部-1?部分提交和硬重置应该足够了,不是保留一些更改并丢弃其他更改吗?
Pradeep

1
Daniel在下面的回答很简单,并且看起来是正确的方法。
Umang

309

我相信您可以使用以下方法最简单地做到这一点:

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.

1
另外,如果您不想选择性地执行此操作,则可以使用“ git checkout-<file> ...”放弃更改。
db42 2011年

它处理目录吗?
bbum 2012年

1
当我放弃更改时,这对我来说似乎失败很多(“错误:补丁<file>失败,”错误:<file>补丁不适用”)。奇怪的是,a在修补程序模式下使用该选项丢弃整个文件时,我会收到那些错误,但git checkout -- <file>仍能按预期工作。有人知道为什么吗?
chrnola 2014年

如果已经对文件进行了修补,则我会多次遇到该错误,因此交互式修补程序与当前文件的已应用修补程序已过时。如果我不小心两次丢掉一块大块皮革,就在使用源代码树之类的GUI工具时发生了这种情况。第二次会产生该错误。
菲特

3

您可以运行git diff该文件,保存所生成的差异,修改或移除你的变化希望保存,然后运行它通过patch -R撤消剩余的diff。

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

我的补丁文件中有2个大块,并删除了一个。不知道是什么原因,但是补丁-R一直被拒绝。
Pradeep

2
您在另一个注释中提到,该注释git diff显示整个文件已更改。当您使用与之前不同的行尾保存文件时,通常会发生这种情况。这也将导致patch拒绝补丁文件。听起来像发生了什么吗?
格雷格·希吉尔

你是对的。每当我使用patch命令时,行尾都在切换。我在窗户上,正在使用Cream / Vim。我认为需要首先解决这个问题。
Pradeep

我无法通过Windows补丁解决此问题。尽管我确定这可以奏效,但我更喜欢使用Paolo的食谱。对于喜欢使用git add -i与diffs进行交互的交互式命令。
Pradeep

3

看起来像你想要的

 git revert --no-commit $REVSISON 

然后,您可以使用

 git diff --cached

在提交之前查看要进行的更改(因为还原只是在向前方向上的提交,它复制了过去所做的更改的逆过程)

如果您使用的是纯粹的Git存储库,则可以根据您的目标,使用交互式rebase(git rebase -i)返回到您不喜欢的提交并追溯编辑该提交,以使您不喜欢的更改永远不会发生,但这通常仅是因为您知道您将再也不想看到它了。


我确实将您提到的内容还原到了先前的修订版(对吗?),现在git diff仅显示整个文件已更改。应该显示我所做的编辑吗?
Pradeep

1

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

如果更改仅在您的工作副本中,那么执行此操作的最简单方法是暂存要保留的更改:

git add -i <file>

然后通过签出索引版本来丢弃不想保留的更改:

git checkout -- <file>

如果您不希望上演更改,则先取消上演:

git reset -- <file>

此配方仅将所选更改还原到文件(或您指定的文件),并且不创建任何需要还原的临时提交。

如果只想选择性地应用在先前提交中所做的某些更改,则可以首先将文件重置为先前的提交状态:

git reset <commit_before_first_unwanted_change> -- <file>

然后,您可以按照的先前方法来暂存git add -i <file>要保留的更改,git checkout -- <file>丢弃不需要的更改并git reset -- <file>“ 取消暂存”更改。


0

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

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.