129

In an attempt to achieve git nirvana, I'm spending the day learning how to leverage rebase for situations where I currently merge.

When running through what I consider to be a git 101 flow (which I spell out below), I have to push --force when pushing my changes back to the origin.

I'm not the only one - I know that this is covered ground (see 1,2,3,4,5), and I understand the technical reasons why a force is necessary. My issue is this --- there are many (many) blog entries singing the praises of rebase and how it's changed their lives (see 1,2,3,4 to list a few), but none of them mentions that push --force is part of their flow. However, nearly every answer to the existing stackoverflow questions say things like "yeah, if you're gonna rebase, ya gotta use push --force".

Given the number and religiosity of rebase advocates, I have to believe that using 'push --force' is not an inherent part of a rebase flow, and that if one often has to force their pushes, they're doing something wrong.

push --force is a bad thing.

So here's my flow. In what way could I achieve the same results without a force?

Simple Example

Two branches:

  • v1.0 - a release branch, contains only patches
  • master - everything for the next major release.

I've got a few patch commits and a few commits for the next release.

premerge

I'd like to incorporate the patches into my master so that they're not lost for the next release. Pre-enlightenment I'd simply:

git checkout master
git merge v1.0

But now I'm trying

git checkout master
git rebase v1.0

So now I'm here:

enter image description here

Time for:

git push

No dice.

Community
  • 1
  • 1
Roy Truelove
  • 22,016
  • 18
  • 111
  • 153

6 Answers6

50

Rebasing is a great tool, but it works best when you use it to create fast-forward merges for topic branches onto master. For example, you might rebase your add-new-widget branch against master:

git checkout add-new-widget
git rebase -i master

before performing a fast-forward merge of the branch into master. For example:

git checkout master
git merge --ff-only add-new-widget

The benefit of this is that your history won't have a lot of complex merge commits or merge conflicts, because all your changes will be rebased onto the tip of master before the merge. A secondary benefit is that you've rebased, but you don't have to use git push --force because you are not clobbering history on the master branch.

That's certainly not the only use case for rebase, or the only workflow, but it's one of the more sensible uses for it that I've seen. YMMV.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • 4
    Thanks CG, I think "use it to create fast-forward merges" is the key. It doesn't apply to my case above where I have two live branches - a development branch and a release branch, but it seems to apply very well for temporary topic branches that are only necessary for a limited peroids of time, and then can be deleted once they're merged. Thanks again. – Roy Truelove Jun 18 '12 at 12:44
  • 1
    I do understand this, but the original question remains. I think the actual answer is the one given by [@Fabien Quatravaux](http://stackoverflow.com/questions/11058312/how-can-i-use-git-rebase-without-requiring-a-forced-push#11137857) – IsmailS Mar 21 '14 at 05:45
  • 7
    Well, you would still have to force-push the 1.0 branch, no? At least, that's how things tend to turn out for me all the time. Fabiens method would prevent that from happening. – joerx Jul 27 '14 at 13:14
  • I compared it and looked at the difference with tig: with force push before merge, it shows `[master] [branch-b] {origin/master} {origin/branch-b} b1` whereas without forcepush before `merge --ff-only` it shows `[master] [branch2] {origin/master} {origin/HEAD} b1`. Note the `origin/branch-b` vs `origin/HEAD` difference. – tomyhomie Jul 09 '22 at 01:16
  • This workflow only works in situations where you're allowed to push the main branch up to remote, right? For example, with GitHub, we often lock repos down these days using the "protected branch" feature so that no one is allowed to modify the main branch directly. It has to be modified by GitHub. In that situation, you have to go through the PR workflow where you let GitHub perform either a merge or a rebase from a PR, right? – Matt Welke May 30 '23 at 16:26
29

@CodeGnome is right. You should not rebase master on v1.0 branch but v1.0 branch on master, that will make all the difference.

git checkout -b integrate_patches v1.0
git rebase master
git checkout master
git merge integrate_patches

Create a new branch that points to v1.0, move that new branch on top of master and then integrate the new version of the V1.0 patches to the master branch. You will end up with something like :

o [master] [integrate_patches] Another patch on v1.0
o A patch on v1.0
o Another change for the next major release
o Working on the next major release
|  o [v1.0] Another path on v1.0
|  o A patch on v1.0
| /
o Time for the release

This way to use rebase is recommended by the official git documentation.

I think you are right about git push --force : you should only use it if you made a mistake and pushed something you did not want.

Nakilon
  • 34,866
  • 14
  • 107
  • 142
Fabien Quatravaux
  • 3,737
  • 2
  • 27
  • 33
  • I think this is the best answer for the specific problem in the OP. You create a temporary merge branch and rebase on that, then merge to master and push to origin. The temporary branch doesn't have to be pushed to origin. The only additional advice I would give is to have a develop or qa branch where the merged/rebased code can be qualified. After qualification, this code would then be ff-only merged into master. This allows for easy hotfixing if your qualification process takes too long. This is basically the "git flow" process. – Javid Jamae Mar 17 '15 at 18:23
  • Thanks Fabien, great answer. For the ones of us that just want to integrate the changes into `master` and don't mind merging the feature branch itself, this can be done with: `git checkout my-branch; git rebase master; git checkout master; git merge my-branch` – Siavas Jan 24 '19 at 17:14
25

You have to force push if you rebase, and you have already published your changes, right?

I use rebase a whole bunch, but I either publish to something private where a force push doesn't matter (eg: my own clone on GitHub, as part of a pull request), or I rebase before I push for the first time.

This is the heart of the workflow where you use rebase, but don't force push much: don't publish things until they are ready, don't rebase after you push.

Daniel Pittman
  • 16,733
  • 4
  • 41
  • 34
  • Thanks Dan. Could you let me know how the above should be achieved then? Is this just not a scenario where rebase applies? – Roy Truelove Jun 15 '12 at 21:23
  • 2
    If you isolate all of your work to topic branches, then it sets up a good scenario for rebasing. You `rebase` new pulled changes into your topic branch, but when you've completed that branch's changes, you `merge` the branch back into the main development branch. – redhotvengeance Jun 15 '12 at 21:31
  • 1
    The problem is that you have published the branch - so you need to force push to the repository. You need to give up one of the two: publishing in the way you do, or rebasing. Sorry. – Daniel Pittman Jun 15 '12 at 21:31
  • Sounds like rebasing doesn't work for this scenario. v1.0 isn't a topic branch, it's a release branch, so it will never die and has to be published. – Roy Truelove Jun 15 '12 at 21:36
  • During `PR` reviews you will **always** have published the branch first – Drenai Dec 09 '22 at 12:39
5

I think there's a good use-case for this rebase-then-force-push pattern that's not a result of a mistaken push: working on a feature branch by yourself from multiple locations (computers). I do this often, since I sometimes work at the office on my desktop, and sometimes from home/customer-site on my laptop. I need to rebase occasionally to keep up with the main branch and/or to make merges cleaner, but I also need to force-push when I leave one machine to go work on another (where I just pull). Works like a charm, as long as I'm the only one working on the branch.

8forty
  • 545
  • 4
  • 13
  • 2
    I have this same workflow (working from multiple computers/locations). So, let's assume you are working on a topic branch called 'mytopic'. As long as you always rebase a local throwaway branch (which is merely a branch of mytopic) onto "master" and then merge that back into mytopic, then you never have to force push. OP has a slightly different scenario, so in a case like that a force push might be necessary. However, I think that OP is rebasing the wrong way -- if he did it as I described then no force push would be necessary. – bwv549 Jun 10 '15 at 06:00
4

Here's what I use (assuming your branch name is foobar):

git checkout master              # switch to master
git rebase   foobar              # rebase with branch
git merge -s ours origin/master  # do a basic merge -- but this should be empty
git push origin master           # aaand this should work
redolent
  • 4,159
  • 5
  • 37
  • 47
1

tl;dr merge with shared branches, rebase with individual branches. --force-with-lease is a safer alternative to force and should help you achieve said git nirvana without the destructive nature of force.

A general rule of thumb that I've seen work for various teams' workflows is to use merge for shared branches (I.e., master or develop) and use rebase when working on your own feature branch. Here is a typical life cycle of a feature branch

git checkout master
git checkout -b new-feature
git commit -am "commit new work"
git push -u origin new-feature
# have code reviewed, run CI, etc.,
# meanwhile master has new commits
git checkout master
git pull origin
git checkout new-feature
git rebase -i master # -i for interactive rebase allows you to squash intermediate commits
git push --force-with-lease
git merge master

A plain english version of what we've done here:

  1. Created a new branch off of master
  2. Done work on branch and pushed to remote
  3. rebased off of master
  4. Push work to remote with force-with-lease
  5. merge into master with a very clean git log, reducing clutter from multiple merges from our shared branch to get our branch "caught up" with the latest master (shared branch)

The 4th step is REALLY important and one of the main reasons I started advocating for the use of rebase. force-with-lease checks the remote to see if any new commits have been added. If your git push was proven to be destructive it won't push!

I hope this gives someone more confidence to use rebase.

lucasnad27
  • 11
  • 2