git push --force-with-lease vs. --force

荒凉一梦 提交于 2019-12-17 17:33:38

问题


I am trying to understand the difference between

git push -f

and

git push --force-with-lease

my guess is that the latter only pushes to the remote if the remote does not have commits that the local branch doesn't have?

If there is a better way to phrase the question, lmk, but hopefully it's clear.


回答1:


force overwrites a remote branch with your local branch.

--force-with-lease is a safer option that will not overwrite any work on the remote branch if more commits were added to the remote branch (by another team-member or coworker or what have you). It ensures you do not overwrite someone elses work by force pushing.

I think your general idea surrounding the command is correct. If the remote branch has the same value as the remote branch on your local machine- you will overwrite remote. If it doesn't have the same value- it indicates a change that someone else made to the remote branch while you were working on your code and thus will not overwrite any code. Obviously if there are additional commits in remote then the values won't be the same.

I just think of --force-with-lease as the option to use when I want to make sure I don't overwrite any teammates code. A lot of teams at my company use --force-with-lease as the default option for a fail-safe. Its unnecessary in most circumstances but will save you lots of headache if you happen to overwrite something that another person contributed to remote.

I'm sure you looked at the docs but there might be some more wordy explanation contained in here:

https://git-scm.com/docs/git-push




回答2:


git push --force is destructive because it unconditionally overwrites the remote repository with whatever one have locally. git's push --force is strongly discouraged as it can destroy other commits already pushed to a shared repository. One of the most common causes of force pushes is when we're forced to rebase a branch.

For example. We have a project with a feature branch that both Alice and Bob are going to work on. They both clone this repository and start work. Alice initially completes her part of the feature, and pushes this up to the main repository. This is all well and good. Bob also finishes his work, but before pushing it up he notices some changes had been merged into master. Wanting to keep a clean tree, he performs a rebase against the master branch. Of-course, when he goes to push this rebased branch it will be rejected. However not realising that Alice has already pushed her work, he performs a push --force. Unfortunately, this will erase all record of Alice's changes in the central repository.

What --force-with-lease does is refuse to update a branch unless it is the state that we expect; i.e. nobody has updated the branch upstream. In practice this works by checking that the upstream ref is what we expect, because refs are hashes, and implicitly encode the chain of parents into their value.

Here is a good post regarding git push --force and git push --force-with-lease.




回答3:


Looking for an answer drawing from credible and/or official sources.

The "compare and swap" mentioned by torek in the comments and in his other answer is further illustrated by the sources of Git itself.

the latter only pushes to the remote if the remote does not have commits that the local branch doesn't have?

That feature was introduced in this commit (Dec. 2013, Git v1.8.5-rc0)

--force-with-lease will protect all remote refs that are going to be updated by requiring their current value to be the same as some reasonable default, unless otherwise specified;

For now, "some reasonable default" is tentatively defined as "the value of the remote-tracking branch we have for the ref of the remote being updated", and it is an error if we do not have such a remote-tracking branch.

So "lease" means:

"force-with-lease": You assume you took the lease on the ref when you fetched to decide what the rebased history should be, and you can push back only if the lease has not been broken.

The sources still mentions "cas":

  • This option was originally called "cas" (for "compare and swap"), the name which nobody liked because it was too technical.
  • The second attempt called it "lockref" (because it is conceptually like pushing after taking a lock) but the word "lock" was hated because it implied that it may reject push by others, which is not the way this option works.
  • This round calls it "force-with-lease".
    You assume you took the lease on the ref when you fetched to decide what the rebased history should be, and you can push back only if the lease has not been broken.

So: "git push --force-with-lease vs. --force"

As I mentioned in "push --force-with-lease by default", as Git 2.13 (Q2 2017) mentions, that the option --force-with-lease can be ignored if a background process (like the ones you find in an IDE with a Git plugin) runs git fetch origin.
In that case, --force prevails.




回答4:


Assuming any pre-receive hooks on the server accept the push, this will always succeed:

git push --force

Whereas this runs a specific client-side check before proceeding:

git push --force-with-lease

You can run the specific check yourself manually. Here's the "lease-checking" algorithm:

  1. Figure out your current branch.

  2. Run git for-each-ref refs/remotes. Take note of the commit-id your git client thinks corresponds to the upstream state of your current branch.

E.g., if you are on branch "foo", take note of the commit-id associated with "refs/remotes/origin/foo".

  1. Determine the actual commit-id of the remote branch on the upstream git server right now.

  2. Only let the "git push" proceed if the commit-ids you extracted from step 2 and step 3 agree. In other words, only proceed if your local git clone's notion of upstream agrees with actual upstream.

There's a sad implication here: since git fetch updates all refs under "refs/remotes/origin/*" to their latest versions, this combination of commands is essentially identical to git push --force:

git fetch

# The command below behaves identically to "git push --force"
# if a "git fetch" just happened!

git push --force-with-lease

To work around this inherent weakness in git push --force-with-lease I try to never run git fetch. Instead I always run git pull --rebase whenever I need to sync with upstream, since git pull only updates a single ref under refs/remotes, keeping the "lease" of --force-with-lease useful.




回答5:


Force-with-lease is not necessarily safe. It just works as Sylvie said. One note: In git a branch is just a pointer on a commit. And commits point to zero or more parent commits. Even if you changed the branch entirely with a hard git reset and a forced push or a push with - - force-with-lease without wanting it, that's not necessarily a big problem. You can use your local git reflog to see how your local tip on the branches (Where was HEAD at that time? ) has changed and reset and push the branch again. Then you only lose new commits on the remote branch, but even they might be restored by the team members.



来源:https://stackoverflow.com/questions/52823692/git-push-force-with-lease-vs-force

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!