关于还原:将单个文件还原为git中的先前版本

Reverting a single file to a previous version in git

本问题已经有最佳答案,请猛点这里访问。

在一个文件中是否有一种方法来执行不同的提交。假设我修改了一个文件5次,我想在提交并推送到一个存储库之后,返回到变更2。

据我所知,唯一的办法就是多留几根树枝,对吗?如果我是对的,几天内我会有几百个分支,所以我可能不太明白。

有人能把它弄清楚吗?


让我们从我们想要做什么的定性描述开始(本·斯特劳布的回答中提到了这一点)。我们已经进行了一些提交,其中五个提交更改了一个给定的文件,我们希望将该文件恢复到以前的版本之一。首先,Git不保留单个文件的版本号。它只跟踪内容—提交本质上是工作树的快照,以及一些元数据(例如提交消息)。所以,我们必须知道哪个提交具有我们想要的文件版本。一旦我们知道了这一点,我们就需要进行一个新的提交,将文件恢复到那个状态。(我们不能只搞历史,因为我们已经推出了这个内容,编辑历史会让其他人感到困惑。)

所以,让我们从找到正确的提交开始。您可以很容易地看到对给定文件进行了修改的提交:

1
git log path/to/file

如果提交消息不够好,并且需要查看每个提交中对文件所做的操作,请使用-p/--patch选项:

1
git log -p path/to/file

或者,如果您喜欢Gitk的图形视图

1
gitk path/to/file

一旦通过视图菜单启动了Gitk,您也可以这样做;视图的选项之一是要包含的路径列表。

无论采用哪种方法,您都可以找到提交的sha1(hash)和所需文件的版本。现在,你要做的就是:

1
2
3
4
# get the version of the file from the given commit
git checkout <commit> path/to/file
# and commit this modification
git commit

(checkout命令首先将文件读取到索引中,然后将其复制到工作树中,因此无需使用git add将其添加到索引中,以备提交。)

如果您的文件可能没有简单的历史记录(例如重命名和复制),请参阅VONC的精彩评论。git可以被引导以牺牲速度更仔细地搜索这些东西。如果你相信历史很简单,你就不用费心了。


Git非常灵活。你不应该需要成百上千的分支来完成你的要求。如果您希望将状态一直恢复到第二个更改(实际上这是一个已经提交和推动的更改),请使用git revert。比如:

1
git revert a4r9593432

其中a4r9593432是要退出的提交的哈希的起始字符。

如果提交包含对许多文件的更改,但只想还原其中一个文件,则可以使用git reset(第2或第3个表单):

1
2
3
4
5
git reset a4r9593432 -- path/to/file.txt
# the reverted state is added to the staging area, ready for commit
git diff --cached path/to/file.txt        # view the changes
git commit
git checkout HEAD path/to/file.txt        # make the working tree match HEAD

但这相当复杂,Git重置很危险。如Jefromi所建议的,用git checkout 代替。

如果只想查看commit x中的文件,可以使用git show

1
git show a4r9593432:path/to/file.txt

对于所有命令,除了通过提交散列(请参见git用户手册中的命名提交)引用提交之外,还有许多方法可以引用提交。


Git不考虑文件版本。Git中的一个版本是整个树的快照。

考虑到这一点,您真正想要的是一个树,其中包含大多数文件的最新内容,但其中一个文件的内容与5个提交之前的内容相同。这将以新提交的形式出现在旧提交的基础上,树的最新版本将拥有您想要的内容。

我不知道是否有一行程序可以将单个文件恢复到5个提交之前的内容,但是Lo-Fi解决方案应该有效:签出master~5,将文件复制到其他地方,签出master,将文件复制回,然后提交。


您可以采用一个diff来撤消您想要的更改并提交它。

例如,如果要撤消范围from..to中的更改,请执行以下操作

1
2
3
git diff to..from > foo.diff  # get a reverse diff
patch < foo.diff
git commit -a -m"Undid changes from..to".


摘自:http://git.661346.n2.nabble.com/revert-a-single-commit-in-a-single-file-td6064050.html

1
2
3
4
5
 git revert <commit>
 git reset
 git add <path>
 git commit ...
 git reset --hard # making sure you didn't have uncommited changes earlier

它对我很管用。