【问题标题】:Remove first pushed commit of a branch删除分支的第一个推送提交
【发布时间】:2020-05-11 13:32:43
【问题描述】:

我有一个场景,我想撤消分支上的第一次提交。 一个简单的解决方案是创建一个新分支,然后将除第一个提交之外的所有提交从我的第一个分支移至新分支并删除旧分支。

我想这可以通过简单地弯曲我的分支底部以更好的方式完成。这样的事情可能吗?我试着把它画出来:

当前:

master   a - b 
branch1       \ revertB - c - d

想要:

master   a - b 
branch1       \ - c - d 

可能吗?:

master a - b ---------------------
skip        \ revertB              \
branch1                             \ - c - d

我不需要 revertB 提交。 我怎样才能做到这一点,或者这是不好的做法? 在此先感谢:)

【问题讨论】:

  • 你想摆脱什么?只是出现在日志中的“revertB”,还是它所做的任何更改?
  • 所有的变化,基本上我只是想删除它
  • rebase 是这样做的方法。

标签: git


【解决方案1】:

git rebase --onto b c branch1

这会将branch1 上的所有提交从c 开始,并将它们重新定位到b

可以把它想象成砍掉一棵树上的树枝,然后重新嫁接 --onto 树的其他部分 (b)。

Git rebase 很强大。学会使用它!特别是交互模式(git rebase -i)。有关其功能的示例,并了解git rebase 的工作原理,请参阅https://stackoverflow.com/a/61411955/8910547the todo file explained 部分

【讨论】:

  • 我认为这正是我想要的。我刚刚查了一个例子,不会是git rebase --onto b revertb 吗?还是我从这里误解了git rebase --onto <newparent> <oldparent>stackoverflow.com/questions/29914052/…
  • 是的,你误解了。相信我。如果您想安全起见,请在 d 创建一个新分支并将其重新设置为试运行(使用我上面的命令,但使用新的分支 ref 而不是 d)。
  • 不完全。不是 。如果您放下脑海中的想法并内化我在回答中给出的“切断分支”类比,那将非常简单。您正在采用由起点和终点 (c d) 和 grafting ONTO b 定义的切割分支。
  • 关于“如果你想安全起见”,只要你没有推送它们,git reflog 总是可以撤消你所做的任何更改
  • @scholl123 很高兴它对你有用。鉴于我更新的答案,让我们都删除上面不再相关的 cmets。长线程让未来的读者感到困惑,SO 的目标是对未来的读者有价值的问题和答案。
【解决方案2】:

如果您还没有推送任何内容,您可以在multiple ways 中修改您的历史记录。如果你推动了你的状态,你需要考虑它会产生的影响!

对于在branch1 之上创建提交但尚未推送它们的任何协作者,您将遇到麻烦。如果除了你之外没有人使用过branch1,你应该没问题。

我找到了最直观的使用方式

git checkout branch1
git rebase -i master

这会打开一个像这样的文本文件。如下所示,将您想要删除的提交更改为drop。然后保存文件并退出。

drop 1a432d7 revertB
pick 2657446 c
pick 8d15847 d

# Rebase 1219262..8d15847 onto 1219262 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

由于我在我的测试存储库中始终为这个答案修改了同一行,所以我遇到了合并冲突。在提交 b 中,我写了b。在提交 c 中,我写了c。在提交 revertB 中,我写了revertB

<<<<<<< HEAD
b
=======
c
>>>>>>> 2657446... c

如果遇到任何合并冲突,您将不得不修复。就我而言,我将文件内容替换为c

暂存固定文件后继续变基:

git add myfile
git rebase --continue

您可以选择修改提交 c 的提交消息。确认后,revertB 将从 branch1 消失。

【讨论】:

  • 这看起来很不错,你能详细说明git rebase -i master中的master是做什么的吗?
  • @scholl123 无需翻出手册进行仔细检查:您告诉 git 将当前分支“重新定位”到其他分支。 IE。不考虑branch1master 分支之前的任何提交。
  • 谢谢@Inigo!你的答案是第一个而且更干净。我刚刚添加了我的,因为交互式 rebase 允许人们不必担心标志的细节,并指出如果分支被其他协作者使用,这是一个坏主意
  • 我真的很喜欢♥️♥️♥️互动模式。如果 OP 想要跳过更多提交、重新排序、挤压等,那么您的回答就是要走的路!
  • 感谢您和@Inigo,我最终使用了您的方法!你们帮了很多忙
【解决方案3】:

“可能吗?”

肯定的。

实现它的一种方法:

# create your "skip" branch
git checkout -b skip <commitHash of "revertB">

# repair branch1 by resetting to master then recreating commits c and d
git checkout -B branch1 master
git cherry-pick c d

【讨论】:

  • 这手动执行 git rebase 自动为您执行的操作,因为 `git rebase under the Covers 会为您保留的提交挑选樱桃。
  • 是的。但在这里从解剖学上做事既不重也不复杂。它清楚地说明了要做什么。这两种方法都属于这里,我很高兴我们联手展示它们。
猜你喜欢
  • 1970-01-01
  • 2012-12-03
  • 2021-11-04
  • 2021-10-30
  • 2021-10-28
  • 2021-06-01
  • 1970-01-01
  • 2018-12-19
  • 2021-06-18
相关资源
最近更新 更多