Cash Dogg
Cash Dogg

Reputation: 175

Difference between git push and git push -f

Please can someone help me explain the difference between git push and git push -f? I do not know which of them is recommended to push your files on github

Upvotes: 6

Views: 27643

Answers (3)

nCessity
nCessity

Reputation: 765

git push -f is short for git push --force. It forces a push when otherwise git would reject your git push because you changed your repo history in your pushing repository. (EDIT: But that is only half the story. Forced pushes also let you overwrite someone else's commits which have been pushed after your last pull.) Use case:

  1. Your repositories are at commit A. You change something locally and commit it (commit B).
  2. You push B to your remote repo. Both are at B now.
  3. You decide to change something again and replace your commit B by commit B'.
  4. You want to push your commit B' to the remote repository. A plain git push will not work. You can now remove commit B from your remote repo and push B' instead with git push --force.

This is ok, if only you are using that remote repo (Or no one else did a pull between B and B'). So, no, not a good idea on github.

Hope that helps.

(EDIT: You can also check the GIT documentation or the GitHub help)

Upvotes: 18

Arnaud Denoyelle
Arnaud Denoyelle

Reputation: 31215

You can get help with every git command with git help [command]. Here is an extract for push and more particularly for the option -f :

-f, --force

Usually, the command refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it. Also, when --force-with-lease option is used, the command refuses to update a remote ref whose current value does not match what is expected.

This flag disables these checks, and can cause the remote repository to lose commits; use it with care.

I made this illustration in order to explain it better:

enter image description here

At step 1), Alice and Bob share the same history which is up to date with origin.

Then, Alice adds one commit and pushes it with git push (Step 2). This is valid since the commit C) has the commit B) as an ancestor.

Then, Bob adds the commit D) on his local branch after the commit B) then tries to push it with git push (Step 3).

This is not valid :

  • On Bob's branch, the ancestor of D is supposed to be B.
  • On Origin, B already has a successor which is not D => conflict.

Bob could (but shall not) use git push -f to replace origin's history with A-B-D. This is bad because it would mess up Alice's history where the successor of B is still C.

Bob shall get locally the commit C (with git fetch) then resolve locally the conflict (with git merge or git rebase) then push the result (with git push)

Upvotes: 8

Mark Adelsberger
Mark Adelsberger

Reputation: 45659

The difference is that git push -f tells git to try to "force" the push. Specifically:

A push is a request to update a remote's refs to reflect the state of the local refs. By default this is only allowed if the local ref is a descendant of the remote ref (that is, if the remote ref is reachable, via parent pointers, from the local ref). This is the normal way that branches grow, and it allows other users to interpret the added commits as new versions that build on the commits they'd already seen on the branch. For example if you have

A -- B -- C <--(origin/master)
           \
            D -- E <--(master)

you can push this and everyone will interpret it as "D and E were added to master" (more or less).

Sometimes you might want to move a branch ref in a way that breaks this rule. Normally this would mean that you've edited history (but see the caveat below). Suppose you have

A -- B -- C <--(origin/master)
 \
  BC -- D <--(master)

In this picture maybe you "squashed" B and C into a single commit, then added commit D. By default git will refuse to attempt such a push; the -f (or --force) option tells it to try. Note that the server might be configured to reject the force push.

Which brings us to that caveat I mentioned: If you do a force push that removes a commit (B and C) from a ref's history, and if anyone else has a clone where the corresponding ref's history includes the removed commit, they will be in a broken state (and if they do "the wrong thing" to recover, they will undo your work). For this reason, it is important to coordinate any history edits with other users that would be affected. See "recovering from upstream rebase" in the git rebase docs for more information.

So to answer your question: The above is how they're different, and the recommended practice is to usually just git push, only using git push -f when (a) there's a specific reason you need it, and, (b) you have the agreement of anyone who would be affected.

Upvotes: 1

Related Questions