25

In my day-to-day git workflow, I have many topic branches, like so:

              o--o--o (t2)
             /
         o--o (t1)
        /
 o--o--o (master)
        \
         o--o--o (t3)

When I pull from upstream,

              o--o--o (t2)
             /
         o--o (t1)
        /
 o--o--o--n--n--n (master)
        \
         o--o--o (t3)

I want to rebase all my topic branches on top of the new master:

                        o'--o'--o' (t2)
                       /
                  o'--o' (t1)
                 /
 o--o--o--n--n--n (master)
                 \
                  o'--o'--o' (t3)

Currently I do this by hand, using git rebase --onto. In this scenario, the whole update process would be:

$ git checkout master
$ git pull
$ git rebase master t1
$ git rebase --onto t1 t2~3 t2
$ git rebase master t3

This gets even hairier when jumping between various topic branches and adding commits.

Dependencies between topic branches in my case are purely tree-like: no branch depends on more than a single other branch. (I have to eventually upstream dependent patches in some particular order, so I choose that order a priori.)

Are there any tools that can help me manage this workflow? I've seen TopGit, but it seems to be tied quite heavily to the tg patch email-based workflow, which isn't relevant to me.

nornagon
  • 15,393
  • 18
  • 71
  • 85

3 Answers3

10

Pretty much the same question was asked on the git mailing list: Rebasing Multiple branches at once... The linked response has a perl script attached that generates the commands you would need.

If you want this script to be fast and avoid having it tread on your toes, also consider using git-new-workdir to set up a working copy just for automatic rebasing.

If you find yourself resolving the same conflicts over and over, consider enabling git rerere.

Having said all that, here is an alternate recipe:

# Construct a placeholder commit that has all topics as parent.
HEADS="$(git for-each-ref refs/heads/\*)" &&
MAGIC_COMMIT=$(echo "Magic Octopus"$'\n\n'"$HEADS" |
  git commit-tree \
    $(git merge-base $(echo "$HEADS" | sed 's/ .*//' ))^{tree} \
    $(echo "$HEADS" | sed 's/ .*//;s/^/-p /')) &&
git update-ref refs/hidden/all $MAGIC_COMMIT

# Rebase the whole lot at once.
git rebase --preserve-merges master refs/hidden/all

# Resolve conflicts and all that jazz.

# Update topic refs from the rebased placeholder.
PARENT=
echo "$HEADS" |
while read HASH TYPE REF
do
  let ++PARENT
  git update-ref -m 'Mass rebase' "$REF" refs/hidden/all^$PARENT "$HASH"
done
David Barr
  • 189
  • 4
  • 6
    Awesome, thanks! :D I used a slightly modified version of this technique to make a script that rebases just a subtree: https://github.com/nornagon/git-rebase-all – nornagon Mar 01 '12 at 05:31
  • Note that since Git 2.18, `git rebase` now has `--rebase-merges`, which is an improved version of `--preserve-merges` and should generally be used in its place. – torek Mar 10 '21 at 21:21
0

There's a new tool that allows to automate such tasks: git-assembler

Here's a direct link to the example in the documentation for rebasing local branches

You shouldn't dismiss TopGit immediately though. The ability to generate email patches is entirely optional.

tardis
  • 419
  • 3
  • 5
-3

Don't rebase. Start your features from a common point. Merges are way less work in the end.

This is what we do:

http://dymitruk.com/blog/2012/02/05/branch-per-feature/

Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
  • That's nice, but I'm integrating with the Chromium workflow, which is linear. These topic branches are local only, small (typically 1-5 commits each) and short-lived. – nornagon Feb 23 '12 at 09:26
  • Wow, this was a good article to read. +1 Sensible advice about rebasing as well, although there will be reasons to do so in specific circumstances. – jupp0r Feb 23 '12 at 09:30
  • @nornagon in the workflow I have outlined, it applies to small features. There is no difference. Merging is better in general as you will take into consideration code changes and where they came from including moving files. – Adam Dymitruk Feb 23 '12 at 18:54