Search code examples
gitgit-branchgit-rebase

Should I rebase master onto a branch that's been pushed?


We use the feature branch workflow in our small team of developers. We're currently working on a large project, so one of the developers has pushed their feature branch to origin, where everyone else can checkout their own local copy.

[leonard@dev public]$ git branch -avv
  master                        9d53b40 [origin/master] Fix reviews
* responsive                    0c04643 [origin/responsive] Add media queries
  remotes/origin/HEAD           -> origin/master
  remotes/origin/master         9d53b40 Fix reviews
  remotes/origin/responsive     0c04643 Add media queries

When developing on master, we create feature branches (i.e. master_hotfix), then when we're ready to merge it in we first rebase master on to it before doing so. This gives us a nice linear history that we prefer. We thought this would be the best way to do this with our responsive project too, so we would create a new branch (i.e. responsive_some-feature) based on the responsive branch. The same git pull, git rebase responsive responsive_some-feature can then be used here, too.

But we're a bit confused as to whether we should (and if so, at what point) rebase master on to responsive? Before the responsive branch was pushed to origin, rebasing master on to it was simple, but is rebasing master to responsive then responsive to responsive_some-feature correct? When I do, I see (along with a few conflicts) this:

# On branch responsive
# Your branch and 'origin/responsive' have diverged,
# and have 112 and 109 different commit(s) each, respectively.
#
nothing to commit (working directory clean)

Usually at this point I see a clean working directory, where I can then checkout master and merge my feature branch in. Alas, after this rebase the commits from master are in there, with the new commits in responsive coming after them, correctly, but is this the right method? How should I proceed, or should I use a different method to keep responsive up to date with master?

Edit: I've made a graphic to illustrate my workflow better:


Solution

  • TLDR

    Should I rebase master onto a branch that's been pushed?

    No, you should follow the general rule - never rewrite the public history (= never rebase branch that's been pushed).

    In the case of simple feature branches, you are able to rebase them (rewrite history) before the push. Or, at least, you can be sure that only one developer works with the feature branch and do forced push if you have branches have diverged situation.

    In the case of the responsive branch, it is public and used by many developers. So you can not rebase it on top of master, do the regular merge for this branch.

    Note: as mentioned in the comments, you have a bit confusing terminology in your post. So I assume that ...we first rebase master on to it [feature branch]... actually means the opposite and you rebase feature branches on top of master.

    Explanation

    The "normal" (no history rewrite) flow with feature branches look like this:

    1) we have a feature branch 
    
    ... O ---- O ---- A ---- B  master
                       \
                        C       feature-branch
    
    2) we do the merge, usually with merge commit (D)
       sometimes it can be fast-forward without the merge commit
    
    ... O ---- O ---- A -- B -- D -  master
                       \       /
                        -- C --      feature-branch
    

    The flow with re-base:

    1) we have a feature branch 
    
    ... O ---- O ---- A ---- B  master
                       \
                        C       feature-branch
    
    2) we rebase feature branch on top of master
       note, that we changed the history and have new C' commit on 
       the feature branch
    
    ... O ---- O ---- A ---- B  master
                              \
                               C'  branch_xxx (feature branch)
    
    3) we do the merge, master is fast-forwarded since there is nothing new
       on master
    
    ... O ---- O ---- A -- B -- C' -  master (fast forwarded)
                            \  /
                             C'      feature-branch
    

    It works good if there is only one developer who works on the feature branch. So the history rewrite is safe.

    But when you add your responsive branch in, the flow, as I understand, is this:

    1) we have a feature branch 
    
    ... O ---- O ---- A ---- B       master
                       \
                        R1 -- R2     responsive
                               \
                                F1   responsive-feature-branch
    
    2) now see what happens if `responsive-feature-branch` is still active (someone works on it) and we rebase the `responsive` on top of `master`:
    
    ... O ---- O ---- A ---- B                master
                      \       \
                       \       R1' -- R2'     responsive'
                        \
                         R1 -- R2             responsive
                                \
                                 F1           responsive-feature-branch
    

    Do you see the problem? Now you have two responsive branches which are diverged (see also explanation in my post).

    You can push the rebased responsive' using '-f' (force) flag, but what will the developer who works on the responsive-feature-branch do? He'll just have the new upstream history and will have to rewrite his-own local history accordingly.

    You can do this forced update if you are sure that nobody have active branches derived from responsive and everyone will need then update their local repos.

    But I don't recommend this, because you can't guarantee that there are no active sub-branches and someday you'll definitely find that your repository has messed up. I think that pretty linear history not worth the time you'll need to spend on resolving these issues.