724

有没有办法对文件进行不同的提交。假设我修改了一个文件 5 次,并且在我已经提交并推送到存储库之后,我想返回更改 2。

在我的理解中,唯一的方法是保留许多分支,我做对了吗?如果我是对的,我将在几天内拥有数百个分支,所以我可能并不真正理解它。

有人可以澄清一下吗?

4

5 回答 5

1020

让我们从对我们想要做的事情的定性描述开始(Ben Straub 的回答中说了很多)。我们进行了一些提交,其中五个更改了给定文件,我们希望将文件恢复到以前的版本之一。首先,git 不保留单个文件的版本号。它只是跟踪内容——提交本质上是工作树的快照,以及一些元数据(例如提交消息)。因此,我们必须知道哪个提交具有我们想要的文件版本。一旦我们知道了这一点,我们就需要进行新的提交,将文件恢复到该状态。(我们不能只是乱搞历史,因为我们已经推送了这个内容,编辑历史会把其他人弄得一团糟。)

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

git log path/to/file

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

git log -p path/to/file

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

gitk path/to/file

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

无论哪种方式,您都可以使用所需文件的版本找到提交的 SHA1(哈希)。现在,您所要做的就是:

# 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可以被引导更仔细地搜索这些东西,而牺牲速度。如果您确信历史很简单,则无需费心。

于 2010-04-29T00:26:36.583 回答
99

Git 非常灵活。您不应该需要数百个分支机构来完成您的要求。如果您想将状态一直恢复到第二次更改(并且确实是已经提交和推送的更改),请使用git revert. 就像是:

git revert a4r9593432 

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

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

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 reset 很危险。git checkout <hash> <file path>正如 Jefromi 建议的那样,改用它。

如果您只想查看提交 x 中文件的样子,您可以使用git show

git show a4r9593432:path/to/file.txt

对于所有命令,除了通过提交哈希之外,还有很多方法可以引用提交(请参阅Git 用户手册中的命名提交)。

于 2010-04-29T00:29:31.167 回答
11

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

鉴于此,您真正想要的是具有大多数文件的最新内容的树,但其中一个文件的内容与 5 次提交前相同。这将采取在旧提交之上的新提交的形式,并且树的最新版本将具有您想要的内容。

我不知道是否有一个单行程序可以将单个文件恢复为 5 次提交之前的内容,但是 lo-fi 解决方案应该可以工作: checkout master~5,将文件复制到其他地方, checkout master,将文件复制回来,然后犯罪。

于 2010-04-29T00:08:40.420 回答
7

您可以采用差异来撤消您想要的更改并提交。

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

git diff to..from > foo.diff  # get a reverse diff
patch < foo.diff
git commit -a -m "Undid changes from..to".
于 2010-04-29T00:16:02.627 回答
7

从这里提取:http: //git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html

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

它对我来说非常好。

于 2013-10-22T21:10:57.347 回答