3

I know that sometimes when I run git push, I get this error:

error: failed to push some refs
To prevent you from losing history, non-fast-forward updates were rejected

Can someone give an example of a situation where history would be lost if I pushed a non-fast-forward update? From my understanding, when I do git push, git will simply push my commits to the remote repository and not delete any of the existing commits, so how will it lose the history?

Thanks!

Paul Draper
  • 78,542
  • 46
  • 206
  • 285
user1516425
  • 1,531
  • 2
  • 15
  • 21

2 Answers2

5

When you push, you send your commit, but you also update the remote branch.

Say a remote repo is:

A <- B <- C (master)

Now you clone it, make some dev starting with commit A, and end up with:

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

If you force push, the remote repo will look like:

A <- D <- E (master)
  <- B <- C

So commits B and C still exist, but they aren't reachable with a branch. And if someone clones the repo now, he will locally have:

A <- D <- E (master; origin/master)

ie: from his point of view, commits B and C are lost


Edit:

  • "the commits still exist" means:

Say my commit B has the sha1 abcdef. Then, there's a file objects/ab/cdef (at the root of the remote repo, and in the .git directory on my local clone) which represents this commit.

If you push -f, it won't delete this remote file, hence, commit B still exists on the remote repo. (At least, as long as it is not garbage collected)

  • "but they aren't reachable with a branch" implies:

When someone else clones this remote after I pushed force, he'll get this .git/objects/ab/cdef file. However, unless he is looking for it, he won't be aware this commit once existed. For example it will not be displayed by gitk --all.

Community
  • 1
  • 1
gturri
  • 13,807
  • 9
  • 40
  • 57
  • Can you clarif more on `So commits B and C still exist, but they aren't reachable with a branch`? – Anshul Goyal Nov 17 '13 at 09:16
  • 1
    This is the right answer, but the picture can be drawn more clearly. Also if the remote to which one pushes is `--bare` there are a number of situations in which commits `B` and `C` get garbage-collected on the remote. – torek Nov 17 '13 at 14:04
  • @torek Yeah, that was what I was also thinking, that B & C will get GC. But why will that happen only in the case of a bare repo? It should happen in the case of a normal repo also, right? after a suitable time delay? – Anshul Goyal Nov 17 '13 at 14:09
  • @ansh0l: it will happen once there are no references to them. There will generally be branch reflog references for 90 days (on at least some repo clone(s) somewhere—the original author of those commits, if no one else). I meant that the remote is likely to collect them quickly (depends on things like `core.logallrefupdates`, I believe; have not tested this). – torek Nov 17 '13 at 17:00
0

Suppose you push your local master to the remote master.

If your local branch and the remote branch have diverged (both have had commits since last you pulled), how would that be handled?

One way would be to declare the current commit for your local master as the new remote master. But that would loose the history of commits that are currently on the remote master, since they would never appear in the ancestry of your commit.

(I suppose that the "lost" commits would still exist remotely, but they would not be on the master branch.)

Paul Draper
  • 78,542
  • 46
  • 206
  • 285