How to update my feature branch after a force push on the base branch . We only use rebase, merges are forbidden

1.8k Views Asked by At

We are working with a very simple structure in git.

First we have our master branch.

Below we have develop

And finally we can have any feature branch

We only use rebase for updating the history on our branches and then f-forwarding to the above branch.

Weekly, we have our develop branch that has been updated with some features. And this branch is rebased and merged into master (from develop to master).

THE PROBLEM

When we are rebasing and merging develop to master , sometimes there are conflicts and I have to fix them by performing a master rebase into my develop branch. After fixing conflicts I perform a git push --force-with-lease to upload changes to remote.

After this procedure, the history of develop has being changed because of the force push.

The problem resides when another developer was working on a feature branch based on develop but, the one before the force push (develop before the force push).

How can we update the feature branch of this developer with the new history of develop branch. Because, when doing a git rebase develop inside our feature branch. We end up with a lot of conflicts.

4

There are 4 best solutions below

0
On BEST ANSWER

If I understand correctly, the developper was is this situation :

--*--x--*--m <- master
      \
       \
        *--*--f <- develop
               \
                a--b--c <- feature

and after he fetches the update, he reaches :

--*--x--*--m <- master
      \     \
       \     *--*--f' <- develop
        *--*--f
               \
                a--b--c <- feature

To only replay a, b, c on top of develop, apply the command suggested by @Vitali :

  • spot commit f : the original fork point between feature and develop,
  • run : git rebase --onto develop <f> feature

If all goes well, he will reach the following state :

--*--x--*--m <- master
            \
             *--*--f' <- develop
                    \
                     a'--b'--c' <- feature

# only 'a--b--c' are replayed from the original 'feature' branch,
# not '*--*--f'
0
On

There is git rebase --onto which you can find in the question here. Another kind of long way is:

1.

git checkout -b feature1 develop  # this will create a new branch that will be in sync with your current develop
  1. Check the commits on your feature branch and take note of the start and last commit over develop.

git cherry-pick <commitA>^..<commitB>
  1. Conflicts would always be there for you to resolve but I find it less prone to introducing errors. Resolve them.

  2. Once you are satisfied with the current branch, delete the old feature branch and rename feature1 to feature.

0
On

THE PROBLEM : Commits from a deleted integration branch exist in a feature branch. They need to be deleted or reverted.

DETAILED SOLUTION: In the future, change your workflow as follows.

  • Do not merge the integration branch into a feature branch. git pull origin develop
  • Do merge master into a feature branch. git pull origin master
  • Do merge a feature branch into the integration branch named develop. git checkout develop && git merge my-feature

Details

The ff-only option ensures devs only get changes that are fast-forwardable and that their feature doesn't get polluted by transient mutations in the develop branch.

Developers should originate their feature-that-works branch from master.

At the start of work:

git pull
git checkout master
git checkout -b feature-that-works

Now I have a new branch named feature-that-works and I am ready to start coding my feature.

What happens if I pull the integration branch develop directly into my feature-that-works branch? My feature branch gets contaminated with every other work-in-progress that's merged into the integration branch. I don't have control of other work in progress and generally, I don't want it contaminating my clean feature branch. That is why I do not pull from the integration branch named develop into my feature-that-works.

Stay up to date with changes

It's not a problem to pull master into a feature branch. Sometimes I fetch from master several times per day in my continuous deployment project. This is fine!

git checkout feature-that-works
git pull --ff-only origin master

The command above with the --ff-only option will fail if there are conflicts.

What to do when there are conflicts

This next command rebases master under feature-that-works.

git pull -r origin master

When the ff-only option fails due to conflicts, I must rebase my branch on top of master. Another way to say this is that I need to rebase master under my feature branch. This ensures that the master branch can always be fast-forwarded.

By rebasing in my local feature branch it will be possible to replay the commit history from my feature branch onto the master branch without any merge conflicts. I am resolving all conflicts locally, rather than waiting until it's time to apply my changes onto the master branch. If there's a problem, hopefully it's a small one that I can resolve locally, instead of waiting and making it someone else's bigger headache downstream.

Here's another good explanation with a simple visual describing why ff-only is preferred to git merge.

An interesting fact: without the ff-only option the git pull command is actually the same as git fetch + git merge.

Integration

I merge a feature-that-works into develop. As I mentioned before, it does not work the other way around.

git push origin feature-that-works
git fetch
git checkout develop
git reset --hard origin/develop
git pull origin feature-that-works
git push origin develop

The reason I used git reset --hard origin/develop is because the develop branch is mutable. Develop can be force pushed by someone else. I want to make sure that my local develop branch matches the remote upstream branch origin/develop.

That's just about it. Keep in mind that even with good workflow, developers need to communicate and may occasionally have to resolve merge conflicts together with other devs.

0
On

It's straightforward with interactive rebase or git cherry-pick.

I think the interactive rebase is a bit faster. See the section titled Changing Multiple Commit Messages in the git-scm documentation for more details.

Interactive Rebase in Two Steps

  1. Create my-feature-cleanup branch. Omit all of the old work by starting from the master branch.
git checkout master
git checkout -b my-feature-cleanup
  1. Issue the interactve rebase command to rebase the good commits from my-feature into the my-feature-cleanup branch.
git rebase -i origin/my-feature

The above command should open a git-rebase-todo editor window. Choose pick for the commit that you want to keep and drop for the commits that you don't want to keep.

# p, pick <commit> = use commit
# d, drop <commit> = remove commit

Another option

Cherry pick will also work. It's the same idea but may require multiple commands to cherry pick individual commits instead of doing it all at once.

  1. It starts out the same way
git checkout master
git checkout -b my-feature-cleanup
  1. List the commits in my-feature
git log my-feature
commit 02345 Something I did
commit 12345 Merge branch 'X' of 'Y'
commit 22345 A thing someone else did
commit 32345 Another thing I did
  1. Cherry pick individual commits from my-feature beginning with the oldest one
git cherry-pick 32345
git cherry-pick 02345

This will put two commits on my-feature-cleanup.

git log my-feature-cleanup
02345 Something I did
32345 Another thing I did
etc...

Good luck!