将整个开发分支重新定位到新的主分支
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?) 中概述的步骤进行操作。对于每个主题分支,请按照以下步骤操作。
将<common-ancestor>
替换为新创建的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 添加为父字符串)。请注意,这假设历史具有单个根(即,没有发生没有共同祖先的合并)。
【讨论】:
以上是关于将整个开发分支重新定位到新的主分支的主要内容,如果未能解决你的问题,请参考以下文章
将 GitHub 项目的分支发布到新的 NPM 模块,但保留与原始模块合并的选项?