签出旧提交并将其设为新提交 [重复]
Posted
技术标签:
【中文标题】签出旧提交并将其设为新提交 [重复]【英文标题】:Checkout old commit and make it a new commit [duplicate] 【发布时间】:2011-03-23 18:55:13 【问题描述】:在 Git 上,假设我搞砸了我的提交,并且我想将版本 3 之前的提交作为新版本。如果我这样做git checkout xxxx
,它会创建一个新分支,似乎我只能合并它?我可以把它设为新的“主版本”吗?
我想要:
A-B-C-D-E
成为
A-B-C-D-E-F
其中 F 与 C 的内容完全相同
如果我改用git revert xxxx
,好像肯定会有冲突,需要手动解决。
我真正想要的只是在某个时候将旧的提交变成新的提交,不管我的工作目录中有什么或最新的提交。
我该怎么做呢?
【问题讨论】:
只要git checkout <commit-hash> .
不要错过命令中的最后一个点
@IbrahimTayseer 是的,但在该命令之前git rm -r .
是相当必要的,否则如果有任何文件存在于较新版本中但旧版本中不存在,则仍然保留。跨度>
是的,你是对的 :)
不是重复的,IMO,因为这个问题希望将以前的提交保留在线性历史中以供将来参考。我也有同样的需求,下面 svick 的回答对我有用,而“重复”问题的帮助不大。
【参考方案1】:
听起来你只想重置为 C;那就是制作树:
A-B-C
您可以使用reset
:
git reset --hard HEAD~3
(注意:你之前说过三个提交,所以这就是我写的;在你的例子中,C 只是两个提交前,所以你可能想使用HEAD~2
)
如果你愿意,你也可以使用revert
,尽管据我所知你需要一次恢复一个:
git revert HEAD # Reverts E
git revert HEAD~2 # Reverts D
这将创建一个新的提交 F,它的内容与 D 相同,而 G 的内容与 C 相同。如果需要,您可以 rebase
将它们压缩在一起
【讨论】:
您好,感谢您的回答。但是,如果我不想进行硬重置,因为它已经推送到公共存储库了? @huggie 啊。那么你可能想使用revert方法 然后 git push -f 强制推送 这会维护提交“E”并创建一个新的提交“F”吗? @meetalexjohnson revert 方法可以; revert 会进行与您指定的提交相反的新提交,因此它们会取消。第一次还原会使 F 与 E 相反,第二次会使 G 与 D 相反,因此您最终会得到与 C 相同的代码。这就是为什么第二次还原是HEAD~2
而不是 @987654328 @ -- F是第一个之后的head commit,所以需要回2引用D【参考方案2】:
git rm -r .
git checkout HEAD~3 .
git commit
提交后,新 HEAD
中的文件将与修订版 HEAD~3
中的文件相同。
【讨论】:
不,只是git checkout XXXXX
。 rev~n
表示 rev
之前的 n 个修订版。
HEAD~3 后面的点很重要。
这行得通,但我觉得应该有一种更优雅的方式来做到这一点。
对于大型存储库,需要一段时间才能删除所有文件,然后将它们全部检查出来。我觉得 git 应该有办法恢复到旧版本,而不必删除所有内容。但这只是我的看法,这对我来说效果很好,当我在寻找替代方案时,我没有看到更好的方法。
可以在回答中解释rm -r .
的作用吗?【参考方案3】:
到目前为止,其他答案会创建新的提交,以撤消旧提交中的内容。可以返回并“改变历史”,但这可能有点危险。您应该仅在您正在更改的提交尚未推送到其他存储库的情况下这样做。
您要查找的命令是git rebase --interactive
如果你想改变 HEAD~3,你想发出的命令是git rebase --interactive HEAD~4
。这将打开一个文本编辑器并允许您指定要更改的提交。
在尝试使用重要的东西之前,先在不同的存储库上练习。手册页应该为您提供所需的所有其他信息。
【讨论】:
投反对票。 1.该问题明确要求保留较旧的提交,因此这可能是其他答案尝试这样做的原因。 2. 正如你所说,提交可能已经发布,没有必要介绍 cmets 对变基意味着什么。【参考方案4】:git cherry-pick C
其中 C 是 C 的提交哈希。这会将旧提交应用到最新提交之上。
【讨论】:
git cherry-pick C
采用 C 引入的 changes 并将它们应用到 E 之上。这不是 OP 所要求的。他希望文件处于 C 中的确切状态,这是 git checkout
提供的。【参考方案5】:
这正是我想做的。我不确定前面的命令git cherry-pick C
,听起来不错,但似乎你这样做是为了从另一个分支而不是在同一个分支上获取更改,有人试过吗?
所以我做了其他也有效的事情: 我从旧的提交文件中按文件取回了我想要的文件
git checkout <commit-hash> <filename>
例如:
git checkout 08a6497b76ad098a5f7eda3e4ec89e8032a4da51 file.css
-> 这会将文件从旧提交中获取
然后我做了我的改变。我再次承诺。
git status (to check which files were modified)
git diff (to check the changes you made)
git add .
git commit -m "my message"
我使用git log
检查了我的历史记录,并且我仍然拥有我的历史记录以及对旧文件所做的新更改。我也可以推。
请注意,要返回您想要的状态,您需要将提交的哈希放在不需要的更改之前。还要确保在执行此操作之前没有未提交的更改。
【讨论】:
【参考方案6】:eloone 逐个文件地使用
git checkout <commit-hash> <filename>
但您可以通过以下方式更轻松地签出所有文件
git checkout <commit-hash> .
【讨论】:
这会在推送到原点时导致拒绝。 这对我有用。推到原点不是问题。 所以git checkout <commit-hash>
将分离HEAD
(推送被拒绝),git checkout <commit-hash> .
应该从提交到您的工作树中签出.
(所有更改),您可以将其应用为新的提交。您还可以分离 HEAD
并分支该提交。然后它应该在 HEAD
用于新分支,您可以在那里提交。 .
很重要。以上是关于签出旧提交并将其设为新提交 [重复]的主要内容,如果未能解决你的问题,请参考以下文章