CmdrMoozy
CmdrMoozy

Reputation: 3931

Git rebase workflow - adding bugfixes to a "stable" branch

For this project I'm working on, we're using a fairly standard git rebase workflow. That is, we'll do all of our work in a feature branch. After a feature is ready to be tested, someone else will:

git checkout master
git merge feature

We also have a stable branch, which is basically a less bleeding-edge copy of master. After the changes in master have been thoroughly tested by others, someone will then:

git checkout stable
git merge master

The problem I'm having is the following situation:

  1. master has many new commits compared to stable, since a new feature has just been pushed out for testing.
  2. The commits in master are not at all ready to be merged into stable.
  3. A bug is discovered in stable, and needs to be fixed right away.

I can't simply add the bugfix to stable and then rebase master on top of it, as others have checked out master. I can't add the bugfix to master and then merge it into stable, because master contains commits which aren't at all ready for use. And, finally, I don't want to just add the bugfix to the end of both stable and master, because this would make the next git checkout stable && git merge master break.

How can I adjust my workflow to accommodate this situation? I'd like to avoid duplicating commits (i.e., stable ending up with the "same commit" twice, with different commit hashes), or merge commits.

Currently, since this situation doesn't come up very often, I just rebase master onto stable and make sure everyone else that has it checked out is aware. I'm wondering if there's a more clean way to achieve this, however.

Upvotes: 3

Views: 1745

Answers (2)

jthill
jthill

Reputation: 60443

Here's an easy way, or I hope it will seem easy after a bit of study, that avoids the merge commits.

From text and comments I see you're doing the marching-ants trick with master and stable, where the only operation (at least usually) permitted on either of them is a fast-forward merge:

...--X--...S                        stable
            \
             m--...--M              master
                      \
                       f--...--F    feature

What I suggest follows, bear with me when you get to the ugly-looking result of this first part:

git checkout master  -B m-temp   # let's do this with nonce names at first
git revert X
# (maybe **amend** the commit to what X should have been here)

git checkout stable  -B s-temp 
git cherry-pick m-temp

git checkout feature -B f-temp
git cherry-pick m-temp

producing:

...--X--...S---X''                         s-temp
            \
             m--...--M---X'                m-temp
                      \
                       f--...--F---X'''    f-temp

and all your branches have exactly one fix for X on them. This looks like a mess, but

notice what a fast-forward merge really is. When it's time to catch stable up to master, you can do it correctly with either of

git checkout s-temp            # the slow way
git reset --hard @{1}          # . (reset one commit from s-temp, i.e. to S)
git merge m-temp               # .

or get the exact same effect with:

git checkout -B s-temp m-temp  # exactly the same, without the rube goldberg

each of those producing:

             X''  <-- discarded cherry-pick of X'
            /        
...--X--...S---m--...--M---X'               m-temp s-temp
                        \
                         f--...--F---X'''   f-temp

... and your branches still all have exactly one fix for X. When it's time to fast-forward master just do likewise, leaving X' also discarded and X''' the sole X fix in your history, or you can have your feature-branch devs rebase onto X' and discard their own X'''s


Git has a 'description' config item for branches. Here's something useful to put in a post-checkout hook:

cat >>.git/hooks/post-checkout <<\EOF
#!/bin/sh
#
#    if there's a stored note about this checkout, show it:

# $3 = 1 for a full branch checkout
if branch=`git symbolic-ref --short -q HEAD` && test $3 = 1; then
        git config --get-all branch.$branch.description
fi
EOF
chmod +x .git/hooks/post-checkout

and then when you want to remind yourself of something,

git config --add branch.stable.description \
     "reset to commit c0ffee before merging master"

which makes cherry-picking any master fixes you want about as easy as can be. When you want the note gone,

git config --unset branch.stable.description c0ffee

makes all the notes matching regex c0ffee go away.

Upvotes: 2

Ajedi32
Ajedi32

Reputation: 48418

Make the bug fix off of stable, then merge it into both stable and master.

git checkout -b bugfix stable
# Make and commit changes
git checkout stable
git merge bugfix
git checkout master
git merge bugfix

That way, there's only one commit (or set of commits) with the bug fix in it so there shouldn't be conflicts when you merge master into stable later.

Upvotes: 6

Related Questions