0

So as mentioned here a git pull is just fetching the latest and then merging them. Isn't that the same for a git push? ie from the remote...you fetch the local and merge it into the branch?

Or is that you're not merging anything, rather you're totally re-writing history of commits...ignoring whatever was there and just replacing commit lists with a newer one?

(I'm fully aware of when to use git push ie I use when I'm done with a feature in my local. I push into my origin. My question is more about what happens under the hood)

builder-7000
  • 7,131
  • 3
  • 19
  • 43
mfaani
  • 33,269
  • 19
  • 164
  • 293
  • 1
    Pushing doesn't rewrite the history on the remote unless your local branch rewrites history, and even then, I think you need to use the `--force` flag. – Abizern Aug 10 '18 at 14:35
  • 1
    Push and pull are semantically opposites, but not at all symetrical operations in git. You don't rewrite anything when you pull or push (--force is another subject), you add to the existing tree. And there's no merging process happening on remote. Merges are supposed to be dealt with locally, *then* pushed on top of the remote tree. – Romain Valeri Aug 10 '18 at 14:42
  • this is how I see it. If master is 1->2->3 (the numbers of commits) and I checkout to 'featureBranch'...and make some changes and commit then the history of commits on my 'featureBranch' is 1->2->3->4. Hence I've rewritten the history of the commits. And when I push this doesn't the remote need to know of this changed history? @Abizern – mfaani Aug 10 '18 at 14:42
  • 2
    You aren't rewriting history. the original 1->2->3 is still there, you've just added 4 on top of it. This isn't rewriting history, it's adding to it. – Abizern Aug 10 '18 at 14:44
  • 1
    Totally re-writing the history of commits? Replacing commit lists? That would defeat the purpose *entirely*. You have to *tell* it to screw with commit history, and in general, you don't need to. The only common time you screw with history is when you're squashing stuff before sending it up, and even then, things can go very wrong. – Dave Newton Aug 10 '18 at 14:45
  • OK. You aren't rewriting history. the original 1->2->3 is still there, you've just added 4 on top of it. Isn't it the same with a `git merge` ie for both you add to the history of commits. **That's the root of my confusion** @Abizern – mfaani Aug 10 '18 at 14:53
  • 1
    `git push` is a bit like a fast-forward merge. If it's a true merge, it would be rejected and fail. – ElpieKay Aug 10 '18 at 14:54
  • @ElpieKay what's a 'fast-forward' merge? What's a true merge? – mfaani Aug 10 '18 at 14:55
  • @Honey about fast-forward merge and true merge, https://www.git-scm.com/docs/git-merge#_fast_forward_merge – ElpieKay Aug 10 '18 at 15:01
  • 1
    I suspect the main problem here is the naming. The nearest thing there is to the opposite of `git push` is *not* `git pull`, it's actually `git fetch`! Back in the early days of Git they put too many things into the `pull` script, so that pull = fetch + merge. But they did not put the extra step into `push`, so it's just the opposite-of-fetch. (A different VCS, Mercurial, avoided that mistake: its push and pull are opposites. However, someone then added, for a while, `hg fetch` which was pull + merge!) – torek Aug 10 '18 at 15:17

1 Answers1

2

git pull pulls the latest commits from the remote to your local client.

git push pushes your latest local commits from your local client to the remote.

When you push, if your local repository does not have all commits from the remote, the push is rejected, not merged into the remote branch as you seem to think. In this case you must first pull the remote's latest changes and either merge or rebase your local changes. Now your local repository is ahead of the remote and you can proceed to push.

In the special case where local and remote histories match, you could look at the push as symmetrically opposite to the pull, i.e. the remote "pulls" the changes from the local, and you're right that in this case. The merge strategy would be equivalent to pulling new changes from remote (specifically the merge strategy is fast-forward; explained about halfway down this page). However a remote repo doesn't work exactly like a local repo, there's no way to login to the remote and pull; rather the command is being run on the local so we must use the correct verb, push.

mfaani
  • 33,269
  • 19
  • 164
  • 293
nvioli
  • 4,137
  • 3
  • 22
  • 38
  • can you see the comments above and possibly edit your question accordingly. I'm still missing something in the foundation of my git understanding :/ – mfaani Aug 10 '18 at 15:00
  • 1
    See my last paragraph; I think @ElpieKay and I are saying the same thing. And I think you're not as confused as you think. You're correct that a `push` when the previous history is up-to-date is (from the remote's perspective) the mirror equivalent of a `pull` when the previous history is up-to-date. But outside the case when previous history is up-to-date, they differ: `pull` will merge your local changes with the new changes from remote, but `push` will be **rejected**. – nvioli Aug 10 '18 at 15:03
  • added a link to an explanation of fast-forward merges. – nvioli Aug 10 '18 at 15:05
  • when would a pull be rejected? – mfaani Aug 10 '18 at 16:56
  • 1
    A `pull` will never be rejected. You can think of the reason a `push` may be rejected as being because the remote does not want to be forced to make decisions about merging. The remote will happily accept any commits that are "in front of" the current `HEAD`, but if the remote and the local have different historical commits, it just throws its hands up and says "nope, you need to fix this" and rejects the push. In contrast, when pulling, if the remote and the local have different historical commits, the user must complete the merge. This works because there's a human who can make that decision – nvioli Aug 10 '18 at 17:05
  • 1
    You could envision a version control system that made this decision differently, maybe one that attempted to do an automated merge on the remote when histories differed during a `push`, and then either rejected the `push` or asked for user input when a merge conflict existed, but that's simply not the decision that was made in git. – nvioli Aug 10 '18 at 17:08
  • I've read the link. It's a nice way of wording things. Would be correct to say a fast-forward merge happens when you no commits on your local...hence it's really not a merge...more of updating your tree based off the fetch. *true merge* is when you've committed something and your commit and the latest from upstream actually merge? – mfaani Aug 10 '18 at 17:41
  • _pull will never be rejected._ how's that possible? Can't a git merge fail? hence a git pull will also fail... – mfaani Aug 10 '18 at 17:48
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/177823/discussion-between-nvioli-and-honey). – nvioli Aug 10 '18 at 18:31
  • 1
    @Honey: yes, a fast-forward operation isn't really a merge at all. A true merge *can* fail; in this case, a `git pull` that ran `git merge` has a nonzero exit status. Whether to call that a *failed pull* is an open question: half the pull (`git fetch`) worked, and half (`git merge`) failed. – torek Aug 10 '18 at 18:31
  • I'm re-reading all this for better understanding. Would you kindly make an edit into your answer and include [this comment](https://stackoverflow.com/questions/51788755/what-exactly-happens-in-a-git-push-why-isnt-a-git-push-considered-just-like-a#comment90539654_51788923) of yours? It fills an important whole of my understanding – mfaani Aug 12 '18 at 19:23
  • Just a note for myself and others: About your `rebase`ing suggestion. It **moves the head** to the latest commit of master so the local commits of our feature branch will be considered to be after that... – mfaani Jan 21 '19 at 12:49
  • you mean a remote *bare* repo that you can't log into and pull. There is a possibility that the remote is just an ordinary repo (not bare centralized repo). In which you can still pull from there. – Agung Dewandaru Mar 30 '22 at 00:57