2

Before pulling from remote, I'm always making sure that I don't have local commits to avoid conflicts. However, I have experienced this:

admin@localhost ~/home (master) $ git status
# On branch master
nothing to commit, working directory clean

admin@localhost ~/home (master)  $ git pull origin master
remote: Counting objects: 5, done.
remote: Total 5 (delta 4), reused 5 (delta 4), pack-reused 0
Unpacking objects: 100% (5/5), done.
From https://github.com/xxxxxxx
 * branch            master -> FETCH_HEAD
Updating 1234567..qwertyu
Fast-forward
 home/templates/test.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

admin@localhost ~/home (master) $ git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
#   (use "git push" to publish your local commits)

Unpushed commit was shown after I pull from the remote. I checked the unpushed commit using git log origin/master..master and it shows the recent commit that I have pulled from remote. Does this mean that I have to push the same commit twice?


UPDATE: I've fixed the issue by running git fetch. By the way, I'm using git version 1.8.3. Thanks!

Jok
  • 23
  • 4
  • Does the commit in question appear on the server (i.e. github.com web)? – Andrew Marshall Oct 09 '17 at 14:30
  • Have you pushed your local commits to the remote? –  Oct 09 '17 at 14:30
  • 1
    it means you have local commits, but git compare it with fetched origin/master, and it happened after pull. Clean means: you don't have umcommited changes. And anyway you should do pull before push. – Alexan Oct 09 '17 at 14:34
  • Yes, I have pushed my local commit to the remote and it appears on the remote server. I don't have local commits before pulling from remote server. It only appeared after pulling. – Jok Oct 10 '17 at 02:08

1 Answers1

2

If your Git version is very old (before 1.8.4), this behavior is normal.

If your Git version is 1.8.4 or later, this behavior is not normal.

(Use git --version to find out what version of Git is installed.)

There are three (not two) entities in play here

Remember that there are two Gits involved during git fetch: your Git, and another Git your Git calls up over the Internet-phone via https://github.com/xxxxxxx. Your Git has a branch named master. Their Git also has a branch named master. Your Git adds a third entity, a remote-tracking branch, in your own repository, named origin/master.

The purpose of this remote-tracking branch is to remember "where origin's master was, the last time we talked with origin".

Next, note that:

git pull origin master

runs:

git fetch origin master && git merge FETCH_HEAD

In Git versions older than 1.8.4, the first step—the git fetch part—fails to update your remote-tracking branch origin/master when it retrieves new commits from the master on origin.

This turned out to be a mistake, so modern versions of Git, starting as far back as version 1.8.4, now update your origin/master remote-tracking branch "opportunistically" when you fetch from origin's master. In other words, if your Git is not positively ancient, git fetch origin master does update your origin/master. But if it is that ancient, it fails to update your origin/master.

Having updated, or failed to update, your origin/master, your Git then goes on to perform that fast-forward you reported:

Updating 1234567..qwertyu
Fast-forward
 home/templates/test.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

so that your own master matches the master on origin.

If your Git is modern, and updated origin/master during the git fetch step, your Git now compares your master with your origin/master and they match. If your Git is ancient, your Git now compares your master with your origin/master, and—whoa!—your master is ahead of your origin/master! But this is merely because your Git forgot to update its memory of origin's actual master.

To fix it, you can just run:

git fetch origin

or even just:

git fetch

which, even in these truly ancient Git distributions, will get your Git to update its memory of "where master is on origin".

(If you set origin/master as the "upstream" for master, you can stop using git pull entirely by running git fetch && git merge, or shorten your git pull command to just git pull. Both of these do pretty much the same thing at this point, but using git fetch && git merge means you don't have to worry about this minor bug in ancient versions of Git. It also gives you more options, such as not running git merge after all: you can run git rebase instead, of that makes more sense.)

torek
  • 448,244
  • 59
  • 642
  • 775
  • what do you mean "over the Internet-phone"? – Alexan Oct 09 '17 at 15:15
  • @Alexan: How do you converse with someone else? By phone, of course (voice or text, on telephone or smartphone.) So ... how does one Git converse with another Git? – torek Oct 09 '17 at 16:35
  • is it some kind of expression? never heard this before. – Alexan Oct 09 '17 at 16:45
  • I came up with it :-) It's meant to be evocative, to really get across the idea that the two Gits have an actual conversation of sorts. One Git, the sending side, sends hash IDs and the like to the other Git, the receiving side. The conversation starts with a protocol version / options exchange; after that, the sender offers objects and the receiver replies with "send that one" or "I already have that one" until they figure out what needs to be sent. The sender then packs up those objects ("counting... compressing") and sends them. At the end, [continued] – torek Oct 09 '17 at 16:51
  • At the end, the sender and receiver can acknowledge various updates and each can save them in their own references, or for `git push`, the receiver can refuse to make updates based on the results of running Git hooks. – torek Oct 09 '17 at 16:52