将整个开发分支重新定位到新的主分支

Posted

技术标签:

【中文标题】将整个开发分支重新定位到新的主分支【英文标题】:Rebase entire development branch onto new master branch 【发布时间】:2015-09-29 22:07:18 【问题描述】:

我正在使用理论上应该遵循 Gitflow 工作流程的存储库(参见 Vincent Driessen 的 A successful git branching model)。但是,存储库上的初始提交是在 develop 分支上进行的,并且看不到 master 分支。发布时间快到了,我需要创建一个master 分支来反映项目的生产就绪状态,该状态应该从一开始就存在。请记住,develop 分支有多个特性分支。存储库完全是本地的,尚未推送。

我的想法是创建一个孤立分支 master 并将 develop 分支重新定位到它上面,但我不知道该怎么做。

那么,如何创建 master 分支,就好像它是从一开始就创建的一样?

更新:在我的情况下,develop 上的第一次提交不是应该被认为适合生产的提交,因此将其用作初始 master 提交是不明智的。项目之所以处于这种状态,是因为当初决定使用Git的时候并没有使用VCS。

【问题讨论】:

那么,拥有一个 master 就足够了吗,或者您实际上需要一个伪造的初始提交并带有过去的日期? @JSelser 具有正确日期的初始提交会很好,但只要 repo 有效运行,主分支代表项目的生产就绪状态,它就解决了我的问题。 develop 分支是否反映了正确的生产就绪历史?只需git branch master develop。 git 中没有固有的分支基础,只有两个历史不同的地方。 @jthill 不,develop 分支应该代表项目的开发状态。由于从未发布过,并且master 分支不是从一开始就创建的,因此没有代表项目生产就绪状态的分支。 如果开发分支还没有反映您想要的历史记录,重新设置它不会有帮助。绘制您拥有的提交图,记住每个提交都是项目状态的完整快照,并添加您想要反映生产快照的任何新提交。重要的是图表,而不是贴在提示上的标签。您将如何生成您的第一个生产就绪状态提交? 【参考方案1】:

经过一番摆弄,这就是我想出的。这是VonC's answer 的一种更简单的手动方法。

重新定位整个开发分支

假设您有一个分支 develop,其中包含存储库的初始提交,并且您希望重写历史记录,以便 master 分支包含新的初始提交。

首先,如果您的 develop 分支上的初始提交适合作为新 master 分支上的初始提交,那么您只需在此处创建 master 分支即可:

$ git branch master <sha1-of-initial-commit-on-develop>

如果您没有这种奢侈,那么您需要创建一个新的空提交,作为master 的初始提交。

# Create the new master branch
$ git checkout --orphan master
# Clear the working directory (we want the initial commit to be empty)
$ git rm -rf .
# Create the initial commit on master
$ git commit --allow-empty -m "Initial commit"
# Rebase the entire develop branch onto the new master branch
$ git rebase --onto master --root develop

如果有任何分支从 develop 分支出来,它们就会“严重混乱”。这是因为这些分支(我们称它们为主题分支)仍然指向旧的develop 分支,然后才重新设置它的基础。如果你没有从 develop 分支出来的分支,那么你就完成了。

每个主题分支都必须重新基于新的develop 分支。为此,我们将按照另一个问题 (Git: How to rebase to a specific commit?) 中概述的步骤进行操作。对于每个主题分支,请按照以下步骤操作。

&lt;common-ancestor&gt; 替换为新创建的develop 分支上的提交的sha1,主题分支应从该分支分支。

$ git branch temp <common-ancestor>
$ git checkout <topic-branch>
$ git rebase temp
$ git branch -d temp

就是这样!请记住,您不应该基于您正在与其他人合作的分支。

【讨论】:

这看起来确实更简单。 +1【参考方案2】:

理想情况下,您需要将dev 的完整历史记录重写为adding a commit at the start:

# remember the first dev commit (before rebase)
git branch tmp  $(git rev-list --max-parents=0 HEAD)

# first you need a new empty branch
git checkout --orphan master
git rm -rf .

# then you apply the same steps
git commit --allow-empty -m 'root commit master'
git rebase --preserve-merges --onto master --root dev

但是,如“Rebasing a branch including all its children”中所示,这将使所有feature 分支指向它们旧的dev 原点(rebase 之前)。

git branch --contains tmp | \
xargs -n 1 \
git rebase --committer-date-is-author-date --preserve-merges --onto master tmp^

也就是说:任何可以从旧的 dev 第一次提交 (tmp) 访问的分支都需要重新基于 master:任何已经重新基于 master 的常见提交都不会重复。这将重新创建来自 feature 分支的提交,来自新的(重新建立的)dev 分支。


原答案:

您可以简单地从dev 分支的第一次提交创建master 分支。

git branch $(git rev-list --max-parents=0 HEAD) master

(见“How to reference the initial commit?”)

这意味着在dev 上完成的第一次提交也被视为master 的一部分,这并不完全准确,但比重写dev整个历史记录更容易。

【讨论】:

这将是一个可行的解决方案,但在我的情况下,develop 上的初始提交不应被视为项目的生产就绪状态。查看我更新的问题。 @ParkerHoyes 那么变基确实是强制性的:我已经相应地修改了答案。 此方法确实将develop 上的初始提交正确地指向master 上的初始提交,但是在rebase 之后,功能分支不再指向正确的提交。 您更新的解决方案仍以相同的结果结束。功能分支指向旧的 develop 提交,而不是重新定位的。 @ParkerHoyes 该死,我知道我原来的答案要简单得多;)我已经编辑了我的答案以重新调整所有功能分支。【参考方案3】:

来自Git filter-branch documentation。

将提交(通常位于另一个历史记录的顶端)设置为当前初始提交的父级,以便将其他历史记录粘贴到当前历史记录后面:

git filter-branch --parent-filter 'sed "s/^\$/-p <graft-id>/"' HEAD

(如果父字符串为空 - 当我们处理初始提交时会发生这种情况 - 将 graftcommit 添加为父字符串)。请注意,这假设历史具有单个根(即,没有发生没有共同祖先的合并)。

【讨论】:

以上是关于将整个开发分支重新定位到新的主分支的主要内容,如果未能解决你的问题,请参考以下文章

重新定位一个分支,包括它的所有子分支

#001 GIT创建分支

git 主干分支代码能merge到开发分支代码

将 GitHub 项目的分支发布到新的 NPM 模块,但保留与原始模块合并的选项?

sh 将git存储库及其所有分支,标记移动到新的远程存储库,保留提交历史记录

如何使用Git完全回退到以前的版本并保存到新的分支