153

How does git help deal with the scenario below:

I have a task broken down into 2 parts: backend task and frontend task. I make a pull request to merge the backend changes and wait for it to be merged (and address feedback). While waiting, I can't really work on the frontend changes because it depends on backend changes and those are not available on the master branch yet.

What is the best way to pull in changes to frontend changes branch from the backend changes branch while it is still being reviewed?

5
  • 5
    Why can't you write it against your not-yet-reviewed backend code? Commented Jun 29, 2017 at 0:04
  • 1
    Does your team have some sort of agreed-on technique for handling this situation? If not, maybe you should agree on something like this, since it's a fairly common situation. Commented Jun 29, 2017 at 9:59
  • 1
    There is none. That is the reason why I asked this question. I got very good suggestions. I will try out the suggestions and see how they work out for me.
    – sul4bh
    Commented Jun 30, 2017 at 0:21
  • @user253751 Separation of concerns.
    – Robin Hood
    Commented Apr 16, 2020 at 9:06
  • @RobinHood Silly reason. Commented Apr 16, 2020 at 20:13

7 Answers 7

129

Hold on, skip merging

For this approach, you do not want to merge your feature_a into feature_b repeatedly.

Rebasing has been mentioned in other answers, but only for rebasing things onto master. What you want to do in your case is:

  • Start your feature_b from feature_a, i.e.:

    git checkout feature_a
    git checkout -b feature_b
    
  • Whenever feature_a changes while it is waiting to get merged into master, you rebase feature_b on it:

    ... commit something onto feature_a ...
    git checkout feature_b
    git rebase feature_a
    
  • Finally, as soon as feature_a has been merged into master, you simply get the new master and rebase feature_aonto it a last time:

    git checkout master
    git pull origin master
    git checkout feature_b
    git rebase --onto master feature_a feature_b
    

    This final rebase will graft all commits that are dangling from the feature_acommit (which is now irrelevant as it has been merged into master) right onto master. Your feature_b is now a simple, standard branch going right from master.

EDIT: inspired from the comments, a little heads up: if you need to make some change which affects both features, then be sure to make it in feature_a (and then rebase as shown). Do not make it in two different commits in both branches, even if may be tempting; as feature_a is part of the history of feature_b, having the single change in two different commits will be semantically wrong and possibly lead to conflicts or "resurrections" of unwanted code, later.

10
  • 6
    With rebasing on feature_a multiple times, you may later run into problems, when feature_a itself has been rebased in the meantime. As result of running git checkout feature_b; git rebase feature_a you may get conflicts or some funny commits containing commits reverting new changes of feature_a. This is usually solvable by using --interactive and skipping commits taken from the old version of the other branch (I had to do this several times recently).
    – maaartinus
    Commented Jun 28, 2017 at 22:24
  • @maaartinus, thanks for the heads-up, I have not run into such issues myself. As rebase does many more individual steps than a simple merge, there is surely a sightly higher chance for it to create conflicts; on the other hand merge would just be semantically quite wrong to do in this case.
    – AnoE
    Commented Jun 28, 2017 at 22:51
  • 1
    @maaartinus, I have added a small addendum about this (to consistently make changes which need to go into both branches only in the base branch, not in two different commits).
    – AnoE
    Commented Jun 29, 2017 at 7:32
  • 1
    Nice technique. It's how I always do it as well. git rebase --onto FTW :D Commented Jun 29, 2017 at 10:10
  • 1
    A rebase always requires --force on the next push, yes. You'll need to make sure that there are no important changes you want to keep on the origin branch, and possibly inform other developers about this so they are not confused afterwards... @BurakKaymakci
    – AnoE
    Commented Nov 4, 2021 at 9:43
47

I have this problem too sometimes. Git is very flexible. Here's one way you can do it.

Your first branch featureA is up for review.

Your second branch featureB is in development and depends on the code in the featureA branch.

Merge the featureA branch into the featureB branch.

If you make changes to the featureA branch then you should merge the featureA branch into the featureB branch again to incorporate the changes.

You should also make sure to merge featureA into the main trunk first, otherwise when you merge featureB into the main trunk you will inadvertently also merge featureA. Once featureA is merged into the main trunk you can get rid of the featureA branch as featureB only depends on the main trunk now.

I prefer it when my feature branches do not depend on each other but sometimes they do and you have to roll with it.

8
  • This makes sense. Does this allow for undoing the merging of featureA onto featureB if need be?
    – sul4bh
    Commented Jun 28, 2017 at 1:25
  • 8
    There's no undo operation but as @9000 mentions, you could make a new branch and cherry pick the commits you want from featureA into that if you had to start over again. It's good to think of Git branches as disposable. They are cheap and easy, you can always make a new branch. You could even make a test branch off your featureB branch if you wanted to play around with something that you weren't sure about, and then scrap it if it didn't work out, or merge it back down to your featureB branch if it did.
    – Matt
    Commented Jun 28, 2017 at 4:34
  • 9
    Merging will create a mess that will be difficult (not impossible) to roll-back. I'd reather cherry-pick or rebase (ie: cherry-pick everything in featureA at the base of featureB). See 9000's answer. Commented Jun 28, 2017 at 12:47
  • 1
    This creates a complex history that will be a problem for many years to come whenever someone wants to understand what code was changed for featureA and featureB
    – Ian
    Commented Jun 28, 2017 at 20:27
  • 2
    if featureA is updated, featureB should be rebased not merged Commented Jun 29, 2017 at 1:47
33

You already have a branch on which your every feature branch depends, and which keeps changing. It's called master.

The typical way for a feature branch to stay in sync with master is to stay on top of it. When master changes, you normally git fetch origin master:master && git rebase master in your branch's working directory.

You can do the very same thing with another feature branch: keep fetching it and rebasing on top of it.

If, for some reason, you'll need to move your changes to a different branch, you can cherry-pick your commits, which are never mixed with other branch's commits.

3
  • But I think the scenario is that feature-b needs the code that is in feature-a, branching from master isn't going to be very helpful. Where should I start? Should I branch from feature-a and keep those in sync until feature-a is reintegrated with master, and then rebase from master to feature-b? Commented Apr 22, 2019 at 23:53
  • @Sinaesthetic: you can of course base feature-b on feature-a, and do a rebase time after time as feature-a is changing. This is a typical way to make a large change observable: split it into part-A (based off master), part-B (based off part-A), and more if needed. Then make a pull request for each part, and reviewers have easier time looking at smaller, logically grouped pieces.
    – 9000
    Commented Apr 23, 2019 at 3:03
  • will it matter if I rebase part-b with part-a vs. part-b with master in terms of the PR? I just want to make sure my changes aren't showing part-a changes as changes in part-b. Also, if I merge vs. rebase, how will that affect the part-b PR? Every time I think I understand the effects, I get some different result lol Commented Apr 23, 2019 at 23:41
5

In this case where the frontend task has a critical dependency on the backend code, and you want to start work on the frontend before the backend is finalised and accepted on master, I would simply start the frontend task as a feature branch coming off from the backend branch, rather than branching the frontend on master.

A feature branch that lives long enough needs to merge in changes from master occaisionally (to make sure you to reconcile any merge or semantic conflicts as part of dev work on the feature branch, rather than as part of the "review, qa, merge-to-master" process). So you do that on your front end branch, and when the backend work has been accepted to master, you'll get any minor changes that were made to the backend as part of its review/acceptance automatically, by the same route you'd get any other code changes on master.

If it turns out the backend branch needs a lot more work and it continues to change over a period of time before being merged to master (say if major problems are found during review), then you you'd probably want to do periodic merges directly from the backend branch into the frontend branch (so you don't keep basing all of your frontend work on obsolete backend code). This is easy if you're the only developer doing both features (since you know if you yourself make any major changes), but even if both features end up being worked on in parallel by different devs it should be fine; you just have to stay in communication (which you would need to anyway, if you're working on tasks in parallel where one has a critical dependency on the other).

If it turns out that the whole backend branch needs to be abandoned and will never be merged (it sounds like this would be a pretty major deal that would rarely happen), then you either cherry-pick your commits to a new branch coming off master without the backend work, or you apply reverse commits that remove all the backend code to the frontend branch. But as I can see it would be more likely to pause the frontend work until you'd figure out what was going to replace the backend you're throwing out, and then decide what to do.

3

I do not see the problem here.

You already have this every time with your master branch, which keeps changing while features are developed and then merged.

So, in your concrete example, you first create the feature_xxx_backend branch and develop the backend changes. When this is done, the branch is up to review and will be merged into master once the review is complete.

So, simply start another branch, feature_yyy_frontend. You will probably want to branch directly from feature_xxx_backend, so that you have those changes already in your branc. then simply develop the frontend feature asif the branch were master.

When the feature_xxx_backend branch changes, e.g. because there are things that come up during review that need to be adressed, simply do these changes and merge them into the feature_yyy_frontend branch. Then continue on the frontend branch.

Once the review of the backend branch is completed, it gets merged into master. At this point, it would be wise to rebase the feature_yyy_frontend branch onto master, so that the reviewers only need to review the new changes that this branch contributes to master, and not need to re-review the changes made for the backend (which have already been approved).

This can also be done when you have two, three or more dependent branches. If you have two feature branches you depend on, simple make a derived branch that has both feature merged in. Branch from there, develop the third feature, merge both feature branches along the way when each of those change. When both features are done and get merged into either the derived branch, rebase onto that, or if they get merged into master, rebase onto master.

Rebasing (as suggested above) is really powerful and helps keeping a clean log of the changes, making reviews much easier.

2

As Polygnome mentioned, you can actually merge your frontend branch with your backend branch instead of the masters. Even with the current branch setup you have now, you can simply do:

git checkout frontend
git merge backend

or simply

git merge backend frontend

Keep in mind though that if backend changes are not accepted and more work is needed, you'll have to merge updates from the backend into the frontend to avoid conflicts. Once the changes are accepted into the master, you can rebase your frontend on the master to get rid of the backend merge commits.

Technically you could also do everything with rebase, but that will mess up the commit history of your frontend branch. Where I'm coming from, this is considered bad practice. YMMV

5
  • "Weird that nobody mentioned that you can actually merge your frontend branch with your backend branch instead of the masters:" This has already been mentioned, e.g. in my own answer.
    – Polygnome
    Commented Jun 28, 2017 at 14:31
  • @Polygnome frontend does not have to be branched directly from backend. They can both be branched from the master as well, but you can still merge them. So your answer doesn't mention that actually.
    – Joris Meys
    Commented Jun 28, 2017 at 14:41
  • Actually, my answer does not suggest that you branch directlly from backend,it just saiys that thats probably the route to go (since you merge those changes into the frontend branch anyways).
    – Polygnome
    Commented Jun 28, 2017 at 15:04
  • @Polygnome then I misunderstood your answer. Updated especially for you :-)
    – Joris Meys
    Commented Jun 28, 2017 at 15:49
  • I don't know who downvoted this, but please tell me where I'm wrong, so I can learn something too.
    – Joris Meys
    Commented Jun 28, 2017 at 15:52
1

Most answers in here correctly describe the process of merging the changes from the second branch to the first, but they do not address how to minimize the amount of conflicts that you may need to resolve.

Whenever you have two sets of big changes that you want to review individually (like featureA and featureB), create a PR that's NOT meant to be merged, but to gather early feedback on a PoC of featureA.

People will be able to review it quickly (it's just a PoC), and the objective is to validate the general design or approach.

Then, you can keep working on feature A, create a pull request for it and branch and work on feature B.

The big difference is that now you can expect featureA to not change radically: the design and approach were already validated. The code review and required changes may be subtle and local rather than a "woops, you need a different approach". This will minimize the amount of work that you need to do to later on merge featureB on featureA's code, regardless of the method you chose.

Not the answer you're looking for? Browse other questions tagged or ask your own question.