有没有办法对文件进行不同的提交。 假设我已经修改了一个文件5次,并且在我已经提交并推送到存储库之后我想回到更改2。
在我的理解中,唯一的方法是保留许多分支,我有没有做到这一点? 如果我是对的,我会在几天内拥有数百个分支机构,所以我可能真的不理解它。
有人可以清楚吗?
答案 0 :(得分:764)
让我们从对我们想要做的事情的定性描述开始(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
更加谨慎地搜索这些内容,但会牺牲速度。如果你对历史的简单有信心,你就不必费心了。
答案 1 :(得分:70)
Git非常灵活。您不应该需要数百个分支来完成您的要求。如果要将状态一直恢复到第二次更改(确实是已经提交并推送的更改),请使用git revert
。类似的东西:
git revert a4r9593432
其中a4r9593432是您要撤消的提交哈希的起始字符。
如果提交包含对许多文件的更改,但您只想恢复其中一个文件,则可以使用git reset
(第二或第三种形式):
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很危险。正如Jefromi建议的那样,请使用git checkout <hash> <file path>
。
如果您只想查看提交x中的文件内容,可以使用git show
:
git show a4r9593432:path/to/file.txt
对于所有命令,除了通过提交哈希之外,还有很多方法可以引用提交(请参阅Git用户手册中的Naming Commits)。
答案 2 :(得分:7)
Git没有考虑文件版本。 git中的版本是整个树的快照。
鉴于此,您真正想要的是具有大多数文件的最新内容的树,但是一个文件的内容与之前的5个提交相同。这将采用新旧提交的形式,并且最新版本的树将具有您想要的。
我不知道是否有一个单行将单个文件恢复为5个提交前的内容,但是低保真解决方案应该有效:checkout master~5
,将文件复制到其他地方, checkout master
,复制文件,然后提交。
答案 3 :(得分:5)
你可以采取一个差异来撤消你想要的改变并提交它。
E.g。如果要撤消范围from..to
中的更改,请执行以下操作
git diff to..from > foo.diff # get a reverse diff
patch < foo.diff
git commit -a -m "Undid changes from..to".
答案 4 :(得分:4)
从这里提取: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
对我来说非常好。