Rebase entire development branch onto new master b

2020-06-04 03:23发布

问题:

I'm working with a repository that in theory should be following the Gitflow Workflow (see A successful git branching model by Vincent Driessen). However, the initial commit on the repository was made on the develop branch and there is no master branch to be seen. It's nearing release time and I need to create a master branch that reflects the production-ready state of the project which should've been there from the start. Keep in mind that the develop branch has multiple feature branches coming off of it. The repository is entirely local and hasn't been pushed.

My idea was to create an orphan branch master and rebase the develop branch onto it, but I don't know how I'd go about doing that.

So, how can I create the master branch as if it was created from the start?

Update: In my case, the first commit on develop is not a commit that should be considered suitable for production, so using this as the initial master commit would be unwise. The reason that the project is in this state is because it was originally not using a VCS when it was decided to use Git.

回答1:

After some fiddling, this is what I came up with. This is a simpler, manual approach to VonC's answer.

Rebasing an Entire Development Branch

Let's assume you have a branch develop which contains the initial commit of your repository, and you'd like to rewrite history such that a master branch contains the new initial commit instead.

First off, if the inital commit on your develop branch is suitable as the initial commit on the new master branch, then you can simply create the master branch there and you're done:

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

If you don't have that luxury, then you'll need to create a new empty commit that will serve as the initial commit of 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

If there were any branches coming off of the develop branch, they would've been "majorly messed up". This is because those branches (we'll call them topic branches) are still pointing to the old develop branch before it was rebased. If you had no branches coming off of the develop branch, then you're done.

Each topic branch is going to have to be rebased onto the new develop branch. To do this, we're going to follow the steps outlined in another question (Git: How to rebase to a specific commit?). For each topic branch, follow these steps.

Replace <common-ancestor> with the sha1 of the commit on the newly created develop branch where the topic branch should branch off of.

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

And that's it! Keep in mind that you should not rebase on a branch that you're collaborating on with someone else.



回答2:

Ideally, you would need to rewrite the full history of dev by 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

However, as illustrated in "Rebasing a branch including all its children", that would leave all the feature branches pointing at their old dev origin (before rebase).

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

That is: any branch that was accessible from the old dev first commit (tmp) needs to be rebased on master: any common commits already rebased on master won't be repeated. That will recreate the commits from the feature branches, from the new (rebased) dev branch.


Original answer:

You could simply have created the master branch from the first commit of the dev branch.

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

(See "How to reference the initial commit?")

That means the first commit done on dev is also considered part of the master, which isn't entirely accurate, but easier than to rewrite the entire history of dev.



回答3:

From the Git filter-branch documentation.

To set a commit (which typically is at the tip of another history) to be the parent of the current initial commit, in order to paste the other history behind the current history:

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

(if the parent string is empty - which happens when we are dealing with the initial commit - add graftcommit as a parent). Note that this assumes history with a single root (that is, no merge without common ancestors happened).