git-refresh: Automatically rebase current branch onto master

Different people have different workflows with git. Mine is pretty simple.

  1. Branch from master
  2. Hack, hack, hack,
  3. git stash; git checkout master; git pull --ff-only; git checkout $branch; git rebase master; git stash pop
  4. Goto step 2 until done

That step 3 is pretty damned annoying. I try to keep branches short-lived, but I often rebase onto master to ensure a clean merge. Thus, I wrote git-refresh. It does step 3 for me. However, my git-fu is sorely lacking (and my bash scripting ain't great either), so suggestions for improving this code are welcome.

#!/bin/bash

# vim: filetype=sh

prog=$(basename $0)
branch=$(git rev-parse --abbrev-ref HEAD)

if [ "$branch" == "master" ]; then
  echo Already on master. Exiting.
  exit 0
fi

need_to_stash=$(git status --porcelain|grep -v '^??')
if [[ $need_to_stash ]]; then
  git stash save "stashed by $prog"
fi
git checkout master
git fetch -p
git pull --ff-only
git checkout $branch

if [[ $(git rebase master) ]]; then
  if [[ $need_to_stash ]]; then
    git stash pop
  fi
else
  echo git rebase failed.
  if [[ $need_to_stash ]]; then
    echo You have changes stashed by $prog
  fi
fi

7 Comments

Mine is similar but seems less painful, I tend to avoid stash and keep partial changes with the branch which I'll clean up with a rebase interactive...

  1. Branch from origin/master (git co -b my-sooper-feature origin/master)
  2. Hack hack hack
  3. git commit -am "work in progress. tests on foo etc."
  4. git fetch && git rebase origin/master
  5. goto 2

More often than not I'll rebase -i and clean up as I go, but certainly for the last rebase before merge/pull request.

I'm a big fan of git up. I guess it won't help in your case, but the magic stashing and unstashing behaviour is really nice.

The implicit question raised by Mr. Anonymous is valid, though: why use a feature branch if you never ever commit? You could at least consider baby-step-commits that you later interactively rebase into a giant-leap-for-mankind-commit.

git status --porcelain -uno should be the same as your git status --porcelain|grep -v '^??' the long form of -uno is --untracked-files=no if your not into the whole brevity thing.

Like a few of the other commenters my workflow makes keeping long running changes in a stash unattractive. I often keep my work in progress that's not ready for distribution to the team in a working branch with many small commits and then git merge --squash the changes into a single commit.

Being able to specify a different base branch name than 'master' might be handy.

Git v1.8.4 added the --autostash option to git rebase. Using your master as an intermediate branch is not really necessary; you can use origin/master instead. Combine those together and you can do git fetch && git rebase --autostash origin/master.

+1 nnutter. You can use your -p, too:

git fetch -p && git rebase --autostash origin/master

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/