Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Merging a branch of a branch after first branch is squashed when merged to master

Here's a workflow that I commonly deal with at work.

git checkout -b feature_branch
# Do some development
git add .
git commit
git push origin feature_branch

At this point the feature branch is up for review from my colleagues, but I want to keep developing on other features that are dependent on feature_branch. So while feature_branch is in review...

git checkout feature_branch
git checkout -b dependent_branch
# Do some more development
git add .
git commit

Now I make some changes in response to the code review on feature_branch

git checkout feature_branch
# Do review fixes
git add .
git commit
git checkout dependent_branch
git merge feature_branch

Now this is where we get have problems. We have a squash policy on master, which means that feature branches that are merged into master have to be squashed into a single commit.

git checkout feature_branch
git log # Look for hash at beginning of branch
git rebase -i  first_hash_of_branch # Squash feature_branch into a single commit
git merge master

Everything is cool, except with dependent_branch. When I try to rebase dependent branch onto master or try and merge master into it, git is confused by the re-written/squashed history and basically marks every single change in depedendent_branch as a conflict. It's a PITA to go through and basically re-do or de-conflicticize all of the changes in dependent_branch. Is there some solution to this? Sometimes, I'll manually create a patch and apply it off a fresh branch of master, but if there's any real conflicts with that, its even worse to fix.

git checkout dependent_branch
git diff > ~/Desktop/dependent_branch.diff
git checkout master
git checkout -b new_dependent_branch
patch -p1 < ~/Desktop/dependent_branch.diff
# Pray for a clean apply.

Any ideas? I know this happens because of the re-written history during the squash, but that's a requirement that I can't change. What's the best solution / workaround? Is there some magic I can do? Or is there a faster way to do all the steps involved with manually creating the diff?

like image 750
Mike Avatar asked Mar 23 '14 15:03

Mike


People also ask

Can you merge a branch of a branch to master?

Once the feature is complete, the branch can be merged back into the main code branch. First we run git checkout master to change the active branch back to the master branch. Then we run the command git merge new-branch to merge the new feature into the master branch.

Should I squash commits when merging to master?

As a general rule, when merging a pull request from a feature branch with a messy commit history, you should squash your commits. There are exceptions, but in most cases, squashing results in a cleaner Git history that's easier for the team to read.

What happens to a branch once it has been merged into another?

When you perform a merge, you effectively merge one branch into another—typically a feature branch or bug fix branch into a main branch such as master or develop. Not only will the code changes get merged in, but also all the commits that went into the feature branch.

What happens to branch after merge to master?

The answer is: nothing happens to the feature branch as a result of the merge. The new merge commit is added on the current branch (which is master when the merge is done).


2 Answers

A little bit about why this happens:

I'll let O be "original master" and FB be "new master", after a feature branch has been merged in:

Say feature_branch looks like:

O - A - B - C 

dependent_feature has a few extra commits on top of that:

O - A - B - C - D - E - F

You merge your original feature branch into master and squash it down, giving you:

O - FB

Now, when you try to rebase the dependent branch, git is going to try to figure out the common ancestor between those branches. While it originally would have been C, if you had not squashed the commits down, git instead finds O as the common ancestor. As a result, git is trying to replay A, B, and C which are already contained in FB, and you're going to get a bunch of conflicts.

For this reason, you can't really rely on a typical rebase command, and you have to be more explicit about it by supplying the --onto parameter:

git rebase --onto master HEAD~3  # instruct git to replay only the last
                                 # 3 commits, D E and F, onto master.

Modify the HEAD~3 parameter as necessary for your branches, and you shouldn't have to deal with any redundant conflict resolution.

Some alternate syntax, if you don't like specifying ranges and you haven't deleted your original feature branch yet:

git rebase --onto master feature_branch dependent_feature

                                 # replay all commits, starting at feature_branch
                                 # exclusive, through dependent_feature inclusive 
                                 # onto master
like image 57
joshtkling Avatar answered Oct 20 '22 21:10

joshtkling


In this particular case it seems you "know" that only the squashed work of the branch you originally worked on has been put into master.

So you can happily merge by keeping your changes every time when there is a conflict. There is an option for that:

git merge -Xours master

See https://git-scm.com/docs/git-rebase for details more details.

like image 2
nha Avatar answered Oct 20 '22 21:10

nha