我有一个git存储库,看起来像这样:
A -> B -> C -> D -> HEAD
我希望分支的头部指向A,即我希望B,C,D和HEAD消失,并且我希望head与A成为同义词。
听起来我可以尝试进行基准调整(由于我已在两者之间进行了更改,因此不适用)或恢复。但是,如何还原多个提交?我一次还原一次吗?订单重要吗?
git revert
。
我有一个git存储库,看起来像这样:
A -> B -> C -> D -> HEAD
我希望分支的头部指向A,即我希望B,C,D和HEAD消失,并且我希望head与A成为同义词。
听起来我可以尝试进行基准调整(由于我已在两者之间进行了更改,因此不适用)或恢复。但是,如何还原多个提交?我一次还原一次吗?订单重要吗?
git revert
。
Answers:
扩展我在评论中写的内容
一般规则是,您不应重写(更改)已发布的历史记录,因为有人可能会基于此记录进行工作。如果重写(更改)历史记录,则合并它们的更改和对其进行更新时会遇到问题。
因此,解决方案是创建一个新的提交,该提交将还原您要删除的更改。您可以使用git revert命令执行此操作。
您有以下情况:
A <-B <-C <-D <-主<-头
(这里的箭头指的是指针的方向:在提交的情况下是“父”引用,在分支头的情况下是顶级提交(分支ref),在HEAD的情况下是分支的名称)。
您需要创建以下内容:
A <-B <-C <-D <-[(BCD)^-1] <-主控<-头
其中“ [[(BCD)^-1]”表示恢复B,C,D提交中的更改的提交。数学告诉我们(BCD)^-1 = D ^ -1 C ^ -1 B ^ -1,因此您可以使用以下命令获得所需的情况:
$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message"
另一种解决方案是检出 提交A的内容,并提交以下状态:
$ git checkout -f A -- .
$ git commit -a
那么您将遇到以下情况:
A <-B <-C <-D <-A'<-主<-头
提交A'与提交A具有相同的内容,但是是不同的提交(提交消息,父母,提交日期)。
Jeff Ferland的解决方案(由Charles Bailey修改)基于相同的想法,但是使用git reset:
$ git reset --hard A
$ git reset --soft @{1} # (or ORIG_HEAD), which is D
$ git commit
git checkout -f A -- .
将不会删除这些文件,则必须手动执行。我现在应用这个策略,感谢的Jakub
git checkout foo
可能意味着签出分支 foo
(切换到分支)或签出文件 foo(来自索引)。--
用于消除歧义,例如git checkout -- foo
始终关于文件。
git revert --no-commit D C B
git revert
时,不接受多次提交;这是相当新的功能。
我觉得有用的干净方式
git revert --no-commit HEAD~3..
此命令仅还原一次提交即可还原最近的3次提交。
也不会重写历史记录。
git commit
从那里实际上将进行提交。
HEAD~3..
与HEAD~3..HEAD
为此,您只需要使用revert命令,指定要还原的提交范围。
考虑到您的示例,您必须执行以下操作(假设您位于分支“ master”上):
git revert master~3..master
这将使用B,C和D的反向提交在您的本地创建一个新的提交(这意味着它将撤消这些提交引起的更改):
A <- B <- C <- D <- BCD' <- HEAD
git revert --no-commit HEAD~2..
是一种比较惯用的方式。如果您在master分支上,则无需再次指定master。该--no-commit
选项让git尝试一次还原所有提交,而不是用多条revert commit ...
消息乱写历史记录(假设这就是您想要的)。
--no-commit
(因此您为每个还原都提交一个单独的提交),然后将它们全部压缩到一个交互式的rebase中。合并的提交消息将包含所有SHA,您可以使用自己喜欢的提交消息编辑器来排列它们。
与Jakub的答案类似,这使您可以轻松选择要还原的连续提交。
# revert all commits from B to HEAD, inclusively
$ git revert --no-commit B..HEAD
$ git commit -m 'message'
B^..HEAD
,否则B被排除。
git revert --no-commit B^..HEAD
或git revert --no-commit A..HEAD
git reset --hard a
git reset --mixed d
git commit
这将立即使所有这些恢复。给一个好的提交信息。
HEAD
看起来像,A
那么他可能希望索引匹配,所以git reset --soft D
可能更合适。
git checkout A
那么git commit
以上对我没有用,但是这个答案确实有用。
git reset --mixed D
需要?具体为什么reset
?是否因为没有重置为D,HEAD会指向A,导致B,C和D被“悬挂”并被垃圾回收-这不是他想要的吗?但是那为什么--mixed
呢?您已经回答“ --soft
重置不会移动索引...”,因此,通过移动索引,这意味着索引将包含D的更改,而工作目录将包含A的更改-这样a git status
或git diff
(将索引[D]与工作目录[A])将显示该内容;该用户从D转到A?
首先,请确保您的工作副本未被修改。然后:
git diff HEAD commit_sha_you_want_to_revert_to | git apply
然后提交。不要忘记记录恢复的原因。
error: cannot apply binary patch to 'some/image.png' without full index line error: some/image.png: patch does not apply
git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply
git revert A..Z
您会得到error: commit X is a merge but no -m option was given.
我很沮丧,不能仅仅回答这个问题。其他所有问题都与如何正确还原和保存历史有关。这个问题说:“我希望分支的头部指向A,即我希望B,C,D和HEAD 消失,并且我希望head与A成为同义词。”
git checkout <branch_name>
git reset --hard <commit Hash for A>
git push -f
我在阅读Jakub的文章时学到了很多东西,但是公司中的某个人(可以在没有Pull-Request的情况下访问我们的“测试”分支)可以像5个错误的提交一样试图修复并修复和纠正他5个提交之前的错误。不仅如此,还接受了一个或两个“拉取请求”,这很糟糕。算了吧,我找到了最后一个好的提交(abc1234),然后运行了基本脚本:
git checkout testing
git reset --hard abc1234
git push -f
我告诉这个仓库中的其他5个人,他们最好记下最近几个小时的更改以及最新测试中的擦除/重新分支。故事的结局。
git push --force-with-lease
,只有在进行汽化的提交之后或范围内没有其他人提交到分支时,才会重写历史记录。如果其他人使用了该分支,则永远不要重写其历史记录,而应该简单地将提交还原。
这是Jakub回答中提供的解决方案之一的扩展
我遇到的情况是,我需要回滚的提交有些复杂,其中一些提交是合并提交,并且我需要避免重写历史记录。我无法使用一系列git revert
命令,因为我最终在添加的还原更改之间遇到了冲突。我最终使用了以下步骤。
首先,检查目标提交的内容,同时将HEAD留在分支的尖端:
$ git checkout -f <target-commit> -- .
(-确保<target-commit>
将其解释为提交而不是文件;。表示当前目录。)
然后,确定在回滚的提交中添加了哪些文件,因此需要将其删除:
$ git diff --name-status --cached <target-commit>
添加的文件应在行的开头显示为“ A”,并且应该没有其他差异。现在,如果需要删除任何文件,请暂存这些文件以进行删除:
$ git rm <filespec>[ <filespec> ...]
最后,提交还原:
$ git commit -m 'revert to <target-commit>'
如果需要,请确保我们返回到所需状态:
$git diff <target-commit> <current-commit>
不应有任何差异。
git
只用分支的尖端进行HEAD吗?
在共享存储库上还原一组提交的简单方法(人们使用并且您想保留历史记录)是git revert
与git结合使用rev-list
。后者将为您提供一份提交列表,前者将自己进行还原。
有两种方法可以做到这一点。如果要在单个提交中还原多个提交,请使用:
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert -n $i; done
这将还原您需要的一组提交,但是将所有更改保留在工作树上,您应该像往常一样将它们全部提交。
另一种选择是对每个还原的更改进行一次提交:
for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-edit -s $i; done
例如,如果您有一个提交树,例如
o---o---o---o---o---o--->
fff eee ddd ccc bbb aaa
将更改从eee还原为bbb,运行
for i in `git rev-list eee^..bbb`; do git revert --no-edit -s $i; done
我认为一种非常简单,干净的方法可能是:
git checkout -f A
git symbolic-ref HEAD refs/heads/master
git commit
git checkout master; git reset --hard A
吗?否则,您能否进一步解释一下该功能?
如果要临时还原功能的提交,则可以使用以下一系列命令。
git log --pretty = oneline | grep'feature_name'| 切-d''-f1 | xargs -n1 git revert --no-edit
git push -f HEAD~4:master
假设远程分支是master)。是的,您可以像这样推送任何提交。