我有一个Git存储库,看起来像这样:
A <- B <- C <- D <- HEAD
我希望分支的头部指向A,即,我希望B、C、D和head消失,我希望头部与A同义。
听起来我可以尝试重新设置基础(不适用,因为我已经在两者之间进行了更改),也可以恢复。但如何恢复多次提交?我一次回复一个吗?订单重要吗?
我有一个Git存储库,看起来像这样:
A <- B <- C <- D <- HEAD
我希望分支的头部指向A,即,我希望B、C、D和head消失,我希望头部与A同义。
听起来我可以尝试重新设置基础(不适用,因为我已经在两者之间进行了更改),也可以恢复。但如何恢复多次提交?我一次回复一个吗?订单重要吗?
当前回答
首先确保您的工作副本未被修改。
然后:
git diff --binary HEAD commit_sha_you_want_to_revert_to | git apply
然后就承诺吧。不要忘记记录还原的原因。
其他回答
与Jakub的回答类似,这允许您轻松选择要还原的连续提交。
# Revert all commits from and including B to HEAD, inclusively
git revert --no-commit B^..HEAD
git commit -m 'message'
如果你
合并提交和您无法恢复,并且你不介意粉碎你要还原的历史,
那么你可以
git reset --soft HEAD~(number of commits you'd like to revert)
git commit -m "The stuff you didn't like."
git log
# copy the hash of your last commit
git revert <hash of your last (squashed) commit>
然后,当您想要推送更改时,请记住使用-f标志,因为您修改了历史记录
git push <your fork> <your branch> -f
我真的想避免硬重置,这就是我想到的。
A -> B -> C -> D -> HEAD
返回A(后退4步):
git pull # Get latest changes
git reset --soft HEAD~4 # Set back 4 steps
git stash # Stash the reset
git pull # Go back to head
git stash pop # Pop the reset
git commit -m "Revert" # Commit the changes
我发现自己需要恢复一系列的提交,然后重新恢复它们,以帮助团队提出明确的拉取请求,而不必强制推送他们的目标分支(直接提交给)
# checkout the branch that should be targeted
git checkout $branch_target
# revert the commits in $branch_target to some $count where
# $count is the number of commits to revert
# cut is used to slice just the commit hash field from each line of output
# xargs runs the command once for each line of input, reversing the commits!
git log --oneline -n $count | cut -d' ' -f1 | xargs git revert
# check out the branch which should be the source of the pull request
git checkout -b $branch_for_pull
# revert the revert commits
# $count is that same number of commits being reverted (again)
git log --oneline -n $count | cut -d' ' -f1 | xargs git revert
# push branches up and go off to create PR in whatever web UI
git push --set-upstream origin $branch_for_pull # it's new!
git checkout $branch_target
git push # if this branch wasn't pushed, just fix the issue locally instead..
因为这会以相反的顺序将所有提交从HEAD还原为git-log-n$count,所以它可以很好地、干净地处理任何数量的提交
在此状态下从$branch_target查看
% git log --oneline origin/$branch_target
ffff006 (origin/$branch_target, $branch_target) Revert "first commit"
ffff005 Revert "second commit"
ffff004 Revert "third commit"
ffff003 third commit
ffff002 second commit
ffff001 first commit
在此状态下从$branch_for_pull查看
% git log --oneline origin/$branch_for_pull
ffff009 (origin/$branch_for_pull, $branch_for_pull) Revert "Revert "third commit""
ffff008 Revert "Revert "second commit""
ffff007 Revert "Revert "first commit""
ffff006 (origin/$branch_target, $branch_target) Revert "first commit"
ffff005 Revert "second commit"
ffff004 Revert "third commit"
ffff003 third commit
ffff002 second commit
ffff001 first commit
如果意图是用变更集创建N个分支,但它们都被提交到同一个分支,您仍然可以将它们全部还原为基本提交,然后只还原所需的还原,因为变更集应该按逻辑排序(试着说5倍快)
使用像HEAD~7..HEAD~5这样的语法可能有助于描述范围以精确地分割还原-还原分支
在这里,当恢复最后7次提交(gitlog-n7),但在一个分支中恢复5次(gitlog-n 5),然后在另一个gitlogHEAD~12..HEAD~10(12是7次提交+5次提交,假设新的PR分支基于“之前”分支,或FF(未压缩)的结果,将分支“之前”合并到原始目标分支中时,这是有意义的
扩展我在评论中写的内容
一般的规则是,你不应该重写(更改)你已经发布的历史,因为有人可能已经基于它进行了他们的工作。如果你改写(更改)历史,你会在合并他们的更改和更新他们时遇到问题。
因此,解决方案是创建一个新的提交,以恢复您想要删除的更改。您可以使用git-restore命令执行此操作。
您遇到以下情况:
A <-- B <-- C <-- D <-- master <-- HEAD
(这里的箭头指的是指针的方向:提交时的“父”引用,分支头(分支引用)时的顶部提交,head引用时的分支名称)。
您需要创建以下内容:
A <-- B <-- C <-- D <-- [(BCD)-1] <-- master <-- HEAD
其中[(BCD)^-1]表示恢复提交B、C、D中更改的提交。数学告诉我们(BCD
$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message for all of them"
适用于除合并提交以外的所有操作。
另一种解决方案是签出提交A的内容,并提交此状态。也适用于合并提交。但是,添加的文件不会被删除。如果您有任何本地更改,请先将其保存:
$ git checkout -f A -- . # checkout that revision over the top of local files
$ git commit -a
那么您将出现以下情况:
A <-- B <-- C <-- D <-- A' <-- master <-- HEAD
提交A'的内容与提交A相同,但提交不同(提交消息、父级、提交日期)。
杰夫·费兰(Jeff Ferland)的替代解决方案,由查尔斯·贝利(Charles Bailey)修改,基于同样的想法,但使用了git重置。在这里,它被稍微修改了一下,这种方式适用于一切:
$ git reset --hard A
$ git reset --soft D # (or ORIG_HEAD or @{1} [previous location of HEAD]), all of which are D
$ git commit