threads / discuss / 49725

using --force-with-lease after git rebase

Subject: using --force-with-lease after git rebase

## tl;dr

3 messages between Oct 31, 2018 and Nov 1, 2018.

replies: 2people: 3as markdown or json

Alexander Mills· Oct 31, 2018, 19:13 UTC · lore
I have been confused about the need for --force-with-lease after rebasing
Imagine I have a feature branch:

git checkout --no-track -b 'feature' 'origin/dev' git push -u origin feature

I do some work, and then I rebase against origin/dev to keep up to date with the integration branch.

git fetch origin/dev git rebase origin/dev

then I try to push to the remote
git push origin feature
but that is rejected, I have to do:
git push --force-with-lease origin feature

why is that? Why do I need to force push my feature branch to the remote tracking branch after rebasing against the integration branch?

-alex

related question: https://stackoverflow.com/questions/52823692/git-push-force-with-lease-vs-force/53042745#53042745

-- 
Alexander D. Mills
¡¡¡ New cell phone number: (415)730-1805 !!!
alexander.d.mills@gmail.com

www.linkedin.com/pub/alexander-mills/b/7a5/418/
brian m. carlson· Nov 1, 2018, 00:58 UTC · re: Alexander Mills · lore

Re: using --force-with-lease after git rebase

On Wed, Oct 31, 2018 at 12:13:06PM -0700, Alexander Mills wrote:
Show 23 quoted lines
> I have been confused about the need for --force-with-lease after rebasing
> 
> Imagine I have a feature branch:
> 
> git checkout --no-track -b 'feature' 'origin/dev'
> git push -u origin feature
> 
> I do some work, and then I rebase against origin/dev to keep up to
> date with the integration branch.
> 
> git fetch origin/dev
> git rebase origin/dev
> 
> then I try to push to the remote
> 
> git push origin feature
> 
> but that is rejected, I have to do:
> 
> git push --force-with-lease origin feature
> 
> why is that? Why do I need to force push my feature branch to the
> remote tracking branch after rebasing against the integration branch?

When you perform a push to an existing branch, Git checks to make sure that the push is a fast-forward; that is, that your changes are a strict superset of the commits that are in that branch. When you rebase a branch, you rewrite the commits and their object IDs (their hashes). Since you've rewritten some of the commits that were on the version of your branch that you pushed to the server, the commits you want to push are no longer a strict superset, and Git requires a force push.

This provision is in place to prevent data loss. For example, if you and a colleague are both collaborating on a branch that isn't rebased, you would want to avoid pushing changes that overwrote those that your colleague had made. Git making your push fail is its way of helping you realize that there are changes you have not included and making you decide how you want to handle them.

You strictly do not need to use --force-with-lease; you could just use --force instead. But using --force-with-lease over --force when possible ensures that you are overwriting what you think you're overwriting, and not additional working changes that someone else has made, so it's a good practice.

-- 
brian m. carlson: Houston, Texas, US
OpenPGP: https://keybase.io/bk2204
Junio C Hamano· Nov 1, 2018, 01:19 UTC · re: Alexander Mills · lore

Re: using --force-with-lease after git rebase

Alexander Mills <alexander.d.mills@gmail.com> writes:
Show 18 quoted lines
> I have been confused about the need for --force-with-lease after rebasing
>
> Imagine I have a feature branch:
>
> git checkout --no-track -b 'feature' 'origin/dev'
> git push -u origin feature
>
> I do some work, and then I rebase against origin/dev to keep up to
> date with the integration branch.
>
> git fetch origin/dev
> git rebase origin/dev
>
> then I try to push to the remote
>
> git push origin feature
>
> but that is rejected, I have to do:

This all depends on how the "dev" branch at the "origin" remote relate to the branch at "origin" you are updating with the commit at the tip of the "feature" branch. Are you pushing to "feature" branch?

If so, then the rejection is very much expected. At this point, the histories of the "feature" branch at the "origin" remote is seeing would look like this:

    ---X---o---o---o---o---A
        \
         x---x---x---x---B

where (X) is where you started the old iteration of the "feature" branch forking off of the "dev" branch, (A) is the tip of that old iteration of the "feature" branch, and (B) is the tip of the new itertion of the "feature" branch you are trying to update with.

The "origin" repository does not know WHY B is not a fast-forward of A. The only thing it knows is that you are discarding the work done in commits (o) while attempting to publish commits (x). If it is intentional, then that's fine, but it does not know (x) are replacements for (o) due to rebasing, so it errs on the side of the caution.

With the "--force-with-lease=feature:A" option, you can tell the other side: "it is OK if this push does not fast-forward, as long as I am updating from A" [*1*].

"--fore-with-lease" without saying what the commit you are expecting to discard makes Git on the sending side _guess_. Depending on what you do locally, it can make a wrong guess, so I would not recommend such a use, but if you saw it succeed and if you did not lose commits at the "origin", then it may have guessed correctly ;-)

[Footnote]
*1* Telling what the value of 'A' is to the other side is important,
 as you are essentially saying that 'B' has everything you want to
 resurrect from 'A'.  Imagine that somebody else pushed to update
 "feature" at the "origin" remote from 'A' to 'C' (or if you did so
 and forgot about it) and then you tried to push 'B' after rebasing.
                             C
                            /
    ---X---o---o---o---o---A
        \
         x---x---x---x---B
 As far as you (who rebased) were concerned, 'B' is equivalent to
 (or "an improved version of") 'A' and you want the push that does
 not fast-forward to go through to replace 'A' with 'B'.  By telling
 "I am replacing A with B" (instead of saying "I am replacing
 whatever with B", which is what "--force" is), the receiving side
 at the "origin" repository can notice that there was another update
 by somebody else's push to the branch while you are preparing 'B'
 and the tip of "feature" is no longer at 'A', and reject the push
 in order to prevent you from losing the work between 'A' and 'C'.

← back to recent threads