The problem is that git push assumes that the remote branch can be fast-forwarded to your local branch. That is, that the only difference between the local and remote branches is that the local one has some new commits at the end, like:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch
When you perform git rebase, commits D and E are applied to the new base and new commits are created. This means that, after rebase, you have something like:
A--B--C------F--G--D'--E' <- feature-branch
\
D--E <- origin/feature-branch
In this situation, the remote branch can't be fast-forwarded to local. Although, theoretically, the local branch can be merged into remote (as the current state of remote is no longer needed), git push only performs fast-forward merges and therefore it throws an error.
The --force option ignores the state of the remote branch and sets it to the commit you're pushing into it. So git push --force origin feature-branch simply overrides origin/feature-branch with the local feature-branch.
In my opinion, rebasing feature branches on master and force-pushing them back to remote repository is OK as long as you're the only one who works on that branch.
The problem is that git push assumes that the remote branch can be fast-forwarded to your local branch. That is, that the only difference between the local and remote branches is that the local one has some new commits at the end, like:
Z--X--R <- origin/some-branch (can be fast-forwarded to Y commit)
\
T--Y <- some-branch
When you perform git rebase, commits D and E are applied to the new base and new commits are created. This means that, after rebase, you have something like:
A--B--C------F--G--D'--E' <- feature-branch
\
D--E <- origin/feature-branch
In this situation, the remote branch can't be fast-forwarded to local. Although, theoretically, the local branch can be merged into remote (as the current state of remote is no longer needed), git push only performs fast-forward merges and therefore it throws an error.
The --force option ignores the state of the remote branch and sets it to the commit you're pushing into it. So git push --force origin feature-branch simply overrides origin/feature-branch with the local feature-branch.
In my opinion, rebasing feature branches on master and force-pushing them back to remote repository is OK as long as you're the only one who works on that branch.
Instead of using -f or --force developers should use
--force-with-lease
Why? Because it checks the remote branch for changes which is absolutely a good idea. Let's imagine that James and Lisa are working on the same feature branch and Lisa has pushed a commit. James now rebases his local branch and is rejected when trying to push. Of course James thinks this is due to rebase and uses --force and would rewrite all Lisa's changes. If James had used --force-with-lease he would have received a warning that there are commits done by someone else. I don't see why anyone would use --force instead of --force-with-lease when pushing after a rebase.
Git - After Rebase, recommend Push (Force)
git - rebase your own branch and force push - Software Engineering Stack Exchange
Force push and rebase - LLVM Project - LLVM Discussion Forums
git - Why do I need a force push after a rebase? - Stack Overflow
Hi everyone!
I'm wondering what is the best practice when working with squash+rebase. Consider the following example:
I have a master branch, and I create a local feature branch out of it. I'm working on the local feature branch, commiting often, and now it's time to squash and rebase. I did that on my local branch, and now I'm able to fast-forward the changes into my local master. Now that everything local is sorted out, I can push my master into origin.
Question is - what do I do with my local feature branch. The origin history is different from my local feature branch. Should I force push it? I kinda have to if I want to create a Github code-review. What happened after I fixed couple of code-review issues, I need to squash+rebase again and AGAIN force push my local feature branch?
e in your second diagram isn't the same commit as e in your first diagram. It may make the same change (although it doesn't necessarily), and it may have the same message (although it doesn't necessarily), but its ancestor and the contents of the tree are both different, so it's a different commit. Likewise your second f can't possibly be the same commit as your first f, and the same applies to g and h. Normally people explaining rebasing would denote the yellow commits in your second diagram as e', f', g', and h' to show the difference.
When you go to push, the upstream has h and you're pushing h'. h' isn't the same commit as h, and it also isn't a descendant of h (we can't reach h' just by tacking some more commits onto h), so this is called a "non-fast-forward" push.
In the time while h was published as feat1, someone else could have made some more commits i and j, beginning with h. After you push h', they're left with commits that are still descendants of h, which is no longer a part of feat1 (and probably no longer a part of any branch). It's not actually technically hard for them to fix that situation (it's just another rebase, with --onto) but it's an annoyance and it forces people to stop and figure out what's going on, so git puts a roadblock in your way to make sure it's something that you really intended to do.
If you pushed your changes upstream to your feature branch before the rebase, then your local copy will be in a different order to the upstream - hence needing a force push.
However, if you merge your now rebased local copy onto the main branch, it will be a fast forward only merge so can be pushed upstream to main without needing a force.