How can git lose history when pushing a non-fast-forward commit?

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!

  • How can I efficiently navigate a Git repo to follow project development?
  • git clone without objects to do git log
  • How do I reword the very first git commit message?
  • Create a submodule repository from a folder and keep its git commit history
  • SVN history is lost in git
  • Understanding Git Graphs
  • Can I affect the order/column of branches displayed in gitk and Eclipse Egit
  • how to easily select a single commit when a range must be specified?
  • 2 Solutions collect form web for “How can git lose history when pushing a non-fast-forward commit?”

    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.

    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.)

    Git Baby is a git and github fan, let's start git clone.