can't push to branch after rebase

106,560

Solution 1

First, you and those you're working with need to agree whether a topic/devel branch is for shared development or just your own. Other developers know not to merge on my development branches because they'll be rebased at any time. Usually the workflow is as follows:

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                \
                  o-----o-----o       devel1

Then to stay up-to-date with remote I'll do the following:

 git fetch origin
 git checkout master
 git merge --ff origin/master

I do this for two reasons. First because it allows me to see if there are remote changes without needing to switch from my devel branch. Second it's a safety mechanism to make sure I don't overwrite any un-stashed/committed changes. Also, if I can't fast-forward merge to the master branch that means either someone has rebased the remote master (for which they need to be flogged severely) or I accidentally committed to master and need to clean up my end.

Then when remote has changes and I've fast forwarded to the latest I'll rebase:

git checkout devel0
git rebase master
git push -f origin devel0

Other developers then know they'll need to rebase their devel branches off my latest:

git fetch <remote>
git checkout devel1
git rebase <remote>/devel0

Which results in much cleaner history:

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

Don't merge commits back and forth at your whim. Not only does it create duplicate commits and make history impossible to follow, finding regressions from a specific change becomes near impossible (which is why you're using version control in the first place, right?). The problem you're having is the result of doing just this.

Also it sounds like other developers may be making commits to your devel branches. Can you confirm this?

The only time to merge is when your topic branch is ready to be accepted into master.

On a side note. If multiple developers are committing to the same repository you should all consider having named branches to distinguish between developers devel branches. For example:

git branch 'my-name/devel-branch'

So all developers topic branches reside within their own nested set.

Solution 2

You need to force the push as you have moved the commits further down the line git is expecting you to add commits to the tip of the branch. git push -f origin myNewFeature will fix your problem.

Tip: Above is a legitimate usage of force pushing. Never ever rewrite the history on a publicly accessible repository or a lot of people will hate you.

Solution 3

The main thing to keep in mind here is what pull and rebase are doing behind the scenes.

A pull will basically do two things: fetch and merge. When you include --rebase it will do a rebase instead of the merge.

A rebase is pretty much like stashing all of your local changes since you branched, fast forwarding your branch to the latest commit on the target, and unstashing your changes in order on top.

(This explains why you may get multiple conflict resolution prompts when doing a rebase vs the one conflict resolution you may get with a merge. You have the opportunity to resolve a conflict on EACH commit that is being rebased in order to otherwise preserve your commits.)

You never want to push rebased changes to remote branches as this is rewritting history. Ofcoarse, never is a bit strong as there are almost always exceptions. The case that you need to maintain a remote version of your local repository to work on a specific environment for example.

This will require you to push rebased changes at times either using force:

git push -f origin newfeature

Or in some cases your administrator may have removed the ability to force so you must delete and recreate:

git push origin :newfeature
git push origin newfeature

In either case you must be absolutely sure you know what you are doing if someone else is collaborating with you on your remote branch. This may mean that you work together initially with merges and rebase those into a more manageable commit format just before going to master and removing your working branch.

Remember you can almost always fallback on git's GC by taking advantage of:

git reflog

This is a HUGE life saver as you can reset back to a more stable state if you get lost in all of your rebase/conflict management.

Solution 4

You need to perform a forced push, i.e. git push -f origin myNewFeature

Oh, and you better make damn sure that people don't base anything on your dev branch - usually you aren't supposed to publish branches where you are rewriting history at all (or rather do not rewrite history once published). One way would be using a branch name like wip/myNewFeature and then mentioning that wip branches will be rebased to master from time to time.

Solution 5

I agree with MrCholo, and maybe Trevor Norris could consider updating its good answer to replace

git push -f origin devel0

with

git push --force-with-lease origin devel0
Share:
106,560
Matt
Author by

Matt

Updated on November 30, 2020

Comments

  • Matt
    Matt over 3 years

    We use git and have a master branch and developer branches. I need to add a new feature and then rebase the commits to master, then push master to CI server.

    The problem is that if I have conflicts during rebase I cannot push to my remote developer branch (on Github) after the rebase is complete, until I pull my remote branch. This causes duplicate commits. When there are no conflicts, works as expected.

    question: after rebase and conflict resolution, how do I sync up my local and remote developer branches without creating duplicate commits

    Setup:

    // master branch is the main branch
    git checkout master
    git checkout -b myNewFeature
    
    // I will work on this at work and at home
    git push origin myNewFeature
    
    // work work work on myNewFeature
    // master branch has been updated and will conflict with myNewFeature
    git pull --rebase origin master
    
    // we have conflicts
    // solve conflict
    git rebase --continue
    
    //repeat until rebase is complete
    git push origin myNewFeature
    
    //ERROR
    error: failed to push some refs to '[email protected]:ariklevy/dropLocker.git'
    hint: Updates were rejected because the tip of your current branch is behind
    hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
    hint: before pushing again.
    hint: See the 'Note about fast-forwards' in 'git push --help' for details.
    
    // do what git says and pull
    git pull origin myNewFeature
    
    git push origin myNewFeature
    
    // Now I have duplicate commits on the remote branch myNewFeature
    

    EDIT

    So it sounds like this will break the workflow:

    developer1 working on myNewFeature developer2 working on hisNewFeature both use master as main branch

    developer2 merges myNewFeature into hisNewFeature

    developer1 rebases, resolves conflicts, then force pushes to remote branch for myNewFeature

    a couple days later, developer2, merges myNewFeature into hisNewFeature again

    Will this cause the other developers to hate developer1?

  • Matt
    Matt about 11 years
    "Also it sounds like other developers may be making commits to your devel branches. Can you confirm this?" YES they are...
  • Matt
    Matt about 11 years
    You have also brought to my attention another issue. Working between the office and home. I make merges at both places and at the end of the day I push so that I can pick up from where I left off. Then when it's time to rebase, all those commits create confusion. I need to treat my branches as one branch and rebase
  • Trevor Norris
    Trevor Norris about 11 years
    @Matt Yeah, those two problems will really screw up your workflow. For the first, I'd communicate to the other developers that only the owner can commit to a named branched (e.g. 'matt/devel'). IMHO, no two developers should commit to the same branch anyways. Just creates confusion. For the later, rebasing and force pushing should keep the two locations up-to-date.
  • Aurelio
    Aurelio over 8 years
    Great answer. I have a side question, why are you using the --force flag when you do git push -f origin devel0?
  • Trevor Norris
    Trevor Norris over 8 years
    @Nobita When a git push cannot fast-forward (i.e. the sha history does not match up) you must force push to overwrite the previous history with the new history generated from the git rebase.
  • Simon Holmes
    Simon Holmes almost 8 years
    The delete & recreate option above worked nicely for me. No forcing allowed on my repo!
  • Syed Priom
    Syed Priom over 7 years
    I find this the most optimal way to maintain workflow.
  • wei
    wei almost 7 years
    Thanks mate. I used this command to force my rebased local branch to the same remote branch.
  • Admin
    Admin over 5 years
    using git push --force-with-lease is much safer than using git push --force
  • Admin
    Admin over 5 years
    using git push --force-with-lease is much safer than using git push --force
  • ThiefMaster
    ThiefMaster over 5 years
    @MrCholo People won't start using this until git adds a short option for it like -f for a normal forced push :)
  • Admin
    Admin over 5 years
    ha yeah, I used it in an automated script tho
  • Lucaci Sergiu
    Lucaci Sergiu almost 5 years
    git push --force-with-lease origin HEAD - assuming your target branch is already checkouted
  • Nasik Shafeek
    Nasik Shafeek over 3 years
    @LucaciSergiu what does --force-with-lease do?
  • Jeaf Gilbert
    Jeaf Gilbert over 2 years
    Is there a way to mimic this flow but without using git push origin -f?