Home > front end >  Git Workflow for Multiple Feature Branches
Git Workflow for Multiple Feature Branches

Time:08-09

Let's say I'm working on a feature that involves changes to multiple components of a system. As an example, let's say I need to update a daemon, server, and client. My current workflow would leave me with branches/commits like this:

m1---m2---m3  <- master
           \
            d1---d2  <- daemon
                  \
                   s1---s2  <- server
                         \
                          c1---c2  <- client

With these branches, I could create 3 pull requests on GitHub, merging client -> server, server -> daemon, and daemon -> master. This all works fine, until I need to add a commit on a branch other than client. For example, let's say I make a commit on daemon:


m1---m2---m3  <- master
           \
            d1---d2---d3  <- daemon
                  \
                   s1---s2  <- server
                         \
                          c1---c2  <- client

Now I'm left in "rebase hell", where I need to rebase server onto daemon, client onto server, etc. Is there a way to move s1 to d3 and take downstream branches like client with it in one command? Thus leaving a final state like this and my pull requests in tact:


m1---m2---m3  <- master
           \
            d1---d2---d3  <- daemon
                       \
                       s1---s2  <- server
                             \
                             c1---c2  <- client

CodePudding user response:

In theory you should only need to merge daemon and client with master if you're branching in this manner but, it's not really an ideal way to split work unless each upstream change is dependent on the previous component and even then you might want to save integration for the overall feature release/merge rather than doing it at each child component.

In Example 2 all commits but d3 are already in client so you could simplify your workflow(s) to either 1, 2, or 3 steps:

  • Example 1: merging client -> master brings in everything.
  • Example 2: merging client -> master brings in everything but d3. Cherry pick (or rebase commit only) d3 to client or master.
  • Example 2 (alt - simplest): Merging daemon -> client -> master would bring in d3 and server.
  • Example 2 (alt 2): Merge upstream branches (daemon, server) before downstream PR (client -> master).

A safer way to do this might be to simply branch master once to create an integration branch and then branch and merge (when resolving) each component so you can test their interoperability without updating your production branch. This would be where you're doing reviews and then merging that to master once release is ready.

This, of course, means 1 more merge rather fewer but wouldn't involve branching feature chaining and would make it easier to catch bugs before release. Sometimes you don't want the fewest merges or the cleanest history, you want guardrails.

CodePudding user response:

It may feel like it's "rebase hell", but the reality is you only need a single rebase command, and then you simply need to repoint the middle branch(es) to their new respective commits. So that's 1 rebase command followed by n-2 branch resets, where n is the number of PR's (branches) you will have. In your example with 3 branches it's kind of a two-liner:

git rebase d2 client --onto d3
# Now for each middle branch, reset to the corresponding new commit ID:
# Look at the log of client to see the new s2 ID
git branch -f server <new-commit-id-of-s2>

If you had many branches chained in this way or you needed to do this often, surely you could automate the reset portion if desired (e.g. commit messages and author name/dates will be the same, etc). However, considering that branching in this way is (generally) a theoretical anti-pattern, I hope it wouldn't happen often enough to warrant spending too much time automating something that can be done manually quickly enough.

  • Related