清理Git主分支并将一些提交移动到新分支?

42

我在Github上有一个克隆的仓库,其中我为上游创建了一个新功能。问题是,我在我的主分支中进行了操作,该分支还包含我从其他克隆中拉取的其他内容。这完全破坏了我创建合理的拉取请求的能力。

因此,我想做以下事情:

  1. 将我的主分支还原为与上游主分支完全相同。
  2. 创建一个新分支。
  3. 将一些旧的提交移动到新分支。
  4. 从新分支创建拉取请求。

并且,在未来,我会在分支中完成所有工作,并从中创建拉取请求,同时让我的主分支保持不变,并向下合并来自上游的任何内容。

我的问题是:

  1. 这是否是合理的方法?
  2. 我应该如何实现步骤1和3?

我现在有一个新的分支,里面有我的旧东西,我真的只想摆脱我的 origin/master,并通过从 upstream/master 获取所有内容并将其推送到我的 master 中来创建一个新的。我该怎么做呢?但是我一直没有成功。 - Manfred Moser
9个回答

70

创建一个新分支来保存东西

$ git branch old_master

发送到远程备份(以防万一)

$ git checkout old_master
$ git push origin old_master

将本地 master 分支重置到你开始修改内容之前的提交

$ git checkout master
$ git reset --hard 037hadh527bn

上游主分支合并更改

$ git pull upstream master

现在删除远程仓库上的主分支

在 Github 上,这不起作用,必须先进入 fork 的管理员部分,并临时将默认分支设置为其他分支,因为他们试图保护你免受损失。

$ git push origin :master

并重新创建它

$ git push origin master

在 GitHub 上,你现在应该将默认分支设置回 master。


+1 针对那个 GitHub 提示的建议。也许有一天我会感激他们试图拯救我,但这次绕过他们的保护是我所需要的 ;) - c089
我在 git pull upstream master 部分有点困惑。最终我做了以下操作,似乎对我有效:git pull https://github.com/project/project.git master - mrswadge
你如何在Github上找到管理员部分? - Todd Freed

9

这几乎是一个合理的方法,但你可能有点顺序颠倒了。首先要做的是创建一个新分支,使其指向当前的 master,以便不会失去对已经完成工作的方便引用:

git branch mywork-orig master

接下来,你可以将 master 分支重置为上游视图(假设你已经检出了 master 分支):

git reset --hard origin/master

然后,您可以使用预期的更改创建自己的分支:

git checkout -b mywork

您可以从mywork-orig中挑选需要的更改(cherry-pick),并将其发送到拉取请求中。


重置没有起作用。然后我试图将其重置为上游/主分支,因为这正是我想要的。我想在我的本地主分支中拉取上游/主分支,然后将其推送到o origin/master(这是我的克隆github本身)。 - Manfred Moser
别忘了使用 git reflog 来帮助你解决问题! - Dominic Mitchell

6
这个方法很简单,虽然有点晚了,但我没看到有人建议过这样做:
# make sure we're in master
git checkout master
# create new branch from current master
git branch tmp_master
# grab most recent changes from upstream w/o applying them
git fetch upstream
# force reset local master to match upstream/master
git reset --hard upstream/master

你已经将本地更改保存到了 tmp_master ,并强制更新了 master 以匹配最新的 upstream/master 。现在要让 origin/master 看起来像 upstream/master :
git push -f origin master

现在,请您执行cherry-pick命令选择提交,或使用rebase命令将更改合并到当前的master分支上。之后,您已经拥有了新的开发分支。

您想要做的完全是可能的,只是不按您提出的顺序。而且其他人似乎忘记了您可以使用fetch命令获取远程更改,而不必实际应用它们。这使得生活变得更加简单。


3
  1. git reset origin/master:回退到远程主分支的状态。
  2. git checkout -b new-branch:创建并切换到新的分支。
  3. git cherry-pick <hash>:挑选每个提交记录进行合并。
  4. 创建你的拉取请求。

或者你可以这样做:

  • git checkout -b new-branch:创建并切换到新的分支。
  • git rebase -i origin/master:选择需要的提交记录。
  • (挑选需要的提交记录)
  • git checkout master:切换回主分支。
  • git reset origin/master:回退到远程主分支的状态。

git rebase -i 是非常棒的东西。一开始可能有点让人不知所措,但学起来绝对是值得的。 - Tekkub
Rebase让我陷入了合并和冲突的困境,最终我在本地拥有一个不工作的主分支,其中仍然包含我不想要的一些旧提交的内容。 - Manfred Moser
第一条规则:永远不要直接在主分支上工作。这样,如果(或者说是当)你搞砸了事情,只需要在主分支上创建一个新的分支,然后再试一次即可。如果你注意到,Talljoe的指示明确告诉你要检出一个新的分支来完成此操作,并将本地主分支重置为远程主分支所在的位置。 - Tekkub
是的,但问题在于我的Github远程主分支出了问题,我需要将其重置为与上游主分支相同...然后我可以按建议工作,但如何使我的Github主分支干净? - Manfred Moser

2
根据 git push,您可以使用 git push origin +dev:master 来执行以下操作:

使用 dev 分支更新 origin 存储库的 master 分支,允许非快进式更新。这可能会导致 origin 存储库中存在未引用的提交。

我不确定这是否适用于 Github。目前我没有需要清除的内容。 :)
使用 git rebase -i 可以使您的本地 master 分支看起来符合您的要求,然后将结果推送到 Github。
或者,您可以通过 删除 Github 上的 master 分支git push origin :master),然后从您的本地更正后的 master 分支重新填充它。如果 master 分支是默认分支(如 master 分支可能是),则我有一种感觉 Github 可能会阻止您执行此操作。如果是这种情况,请进入存储库的管理部分,并将默认分支暂时更改为其他分支。

非常高效和简单的方法来替换主分支。非常感谢! - Aurélien Bénel

2

@Novelocrat 建议的方法与我几乎完全一致。一定要从当前的 master 分支位置创建一个备份分支:

git branch mywork-orig master

在您的情况下,我认为origin是您的GitHub fork(分支),而upstream是您fork的原始来源。因此,当您本地检出了master后,应该执行以下操作:

git reset --hard upstream/master

这将使它重置到upstreammaster所在的位置。然后,您还必须将其推送到github上的您的分支:

git push origin +master

然后从新重置的master分支创建新的分支,这些分支现在应该与upstream/master相同:

git checkout -b mywork

由于您在旧的master分支上进行了许多合并,因此您可能无法将很多内容挑选到您创建的新功能分支上。请尽可能挑选可以挑选的提交,然后对于无法轻松挑选的提交,简单地(或者不那么简单地)重新创建它们。请保留HTML标签。

git reset --hard upstream/master 似乎无法正常工作。我已经这样做了,但是项目现在甚至无法构建,尽管我可以很好地构建上游的本地克隆。仍然有一些不同。 - Manfred Moser
提示:始终保持一个 gitk --all& 窗口打开,每次运行 CLI 命令之间刷新它。这可以很好地查看每个 head 的位置以及每个命令的作用。 - Hugo Josefson
谢谢。顺便说一句,wewals的答案是解决方案。很快会向您发起拉取请求。下一个发布? - Manfred Moser

1

您可以使用git push命令将任意更改集推送到git存储库中的任意引用。在这种情况下,您需要确定要还原的更改集的哈希,并将其设置为远程存储库中主分支的头部。假设该远程存储库称为origin,则可以使用以下命令,其中XXXX是要还原的更改的哈希:

git push -f origin XXXX:refs/heads/master

-f开关将强制更改,因为默认情况下git不允许您将非快进更改推送到远程存储库,因为如果其他存储库从您的存储库中克隆,则可能会导致严重问题。


那么XXXX将是我想要在我的远程主分支中镜像的上游主分支的最新引用,对吗?这会删除我从主分支创建的分支吗,还是会保留该分支中的旧状态? - Manfred Moser
是的,XXXX 将是您想要成为新远程主分支的最新上游主分支。我不确定它会对您创建的分支产生什么影响。即使没有任何引用,git 存储库仍将包含所有旧信息,因此它很可能会保留下来。为了安全起见,在进行这些更改时,您可以始终克隆您关心的所有内容并将其离线存储,这样如果出现问题,您就有备份了。 - Bryan Kyle

1
如果你想让“master”看起来像“remotes/origin/master”,你可以进行强制拉取。
$ git pull +master:master
   From git://github.com/matthewmccullough/hellogitworld
   + 1d22ca0...2a52e96 master     -> master  (forced update)

0

我有一种逻辑和尽可能安全的方法。假设:

  • 您必须有权力强制更新源上的主分支。
  • 它假定没有其他人拉取即将被删除的任何节点。
  • 您可以在本地修复主分支时防止对源上的主分支进行更新。

将本地错误的主分支移动/重命名为my-bad-master。

git branch -m master my-bad-master

将本地主分支更新为与源主分支相匹配的版本。

git pull origin master:master

将源代码的主分支保存为一个名为 old-master 的分支。
git branch old-master master

为了安全起见,请将旧主分支推送到远程仓库。
git push origin old-master:old-master
checkout master

对主分支进行任何更改。请确保在完成前不要在 origin 上对主分支进行更改!!!

完成后,强制将新的主分支推送到 origin。

git push -f origin master:master

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接