Git: Rebase workflow with remotes involved

Note: I haven’t gone to great pains to make this post beginner-friendly, but if you’re in my situation, you should be able to follow along and understand the problem and how I solve it. Feedback welcome in the comments.

Overview

I’ve been trying to stick strictly to a rebase workflow in Git, rather than using git merge.

This has not been without it perils.

However, I’ve found a workflow that works for me as an individual developer using my own feature branch that I push to a remote. Do not use the following workflow for other situations unless you know what you’re doing.

“Why are you doing this?” and such

The problem: After rebasing using the mainline as a base (git rebase master) you can no longer push the rebased branch to a remote since it won’t fast-forward anymore.

Why would you push it to a remote? Because you have untracked/dirty files that need to stay that way locally. In my case, my Drupal settings.php is in the repository – don’t blame me, I don’t control the client’s internal processes – and it must stay dirty for my local site to function. Rebasing is much easier when you don’t have to worry about such files, though, so I keep a second clone of the repository that I use for rebasing.

Pushing my changes from the dirty repository works fine, naturally, since I don’t rebase there.

But once I rebase in the clean repository, how do I push those changes back to the dirty one without causing a merge?

It actually only takes a few commands, and it is pretty safe as long as everything you want to commit to your feature branch is already committed.

The good part (commands!)

This is what I do:

cd /path/to/clean/repository/clone

git pull (remember, I don’t work on this repository, so it will always fast-forward)

git checkout featurebranch

git rebase master

(fix any conflicts and complete the rebase)

git push -f origin featurebranch (this overwrites the remote with what I now have)

cd /path/to/dirty/repository/clone

git checkout master

git branch -D featurebranch (this deletes the local featurebranch branch)

git checkout featurebranch (you may have to use git checkout -b featurebranch origin/featurebranch – I don’t know what differentiates if you have to or not)

Explanation and conclusion

So basically, I’m recreating the local branch from the remote branch. Then I continue developing and rinse/repeat when I need to integrate changes from the mainline or when I’m done with my feature and want to make sure it will fast-forward into the mainline. I finally developed this workflow after finding I always had to merge my feature branch into the mainline in the end; it would never fast-forward. This is because I was running git rebase origin/featurebranch from within the feature branch, since then it would let me push. This basically defeated the purpose of rebasing since it would rebase the new commits from the mainline on top of mine. I wanted mine on top of the new mainline commits.

Hope this helps some poor soul out there who’s in the same boat I was.