I did some work in a topic branch, with two intermediate commits before finishing the work. Then I went back to master and merged my topic branch. I'm in the habit of merging with --no-commit
, so I can check that everything is ok before committing, but this was a fast-forward and I didn't stop it with --no-ff. Now "git status" tells me that there are 5 commits to push, but "git log" only shows 3 – the number of commits I did on the topic branch:
$ git status
On branch master
Your branch is ahead of 'origin/master' by 5 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
$ git log
commit f4474af2add220b1c2f0bf07d92f5035cef622ef (HEAD -> notifiche, master)
Author: Francesco Marchetti-Stasi <f.marchettistasi@***>
Date: Fri Dec 10 14:55:48 2021 0100
[...]
commit b63a44f7c1266a53a0e5c91a3395fc9eb75d9bd2
Author: Francesco Marchetti-Stasi <f.marchettistasi@***>
Date: Tue Dec 7 16:46:59 2021 0100
[...]
commit beb5d335e0ac35184b6a8e78bf45627e705a2a9b
Merge: 1f16a0d 025f660
Author: Francesco Marchetti-Stasi <f.marchettistasi@***>
Date: Tue Dec 7 16:46:18 2021 0100
[...]
commit 025f660ebc22b2d3bee00c691657c6e7318fcf50 (origin/master, origin/HEAD)
Author: Francesco Marchetti-Stasi <f.marchettistasi@***>
Date: Tue Dec 7 11:44:48 2021 0100
[...]
commit 1f16a0dcd96862b0ca75d3f3ca896ad755ccf29e
Author: Francesco Marchetti-Stasi <f.marchettistasi@***>
Date: Thu Nov 25 09:38:21 2021 0100
[...]
Is this normal? Are there some "hidden" commits I am not seeing?
In your answers please consider I may need to push my commits, but I guess that shouldnt' change local commit history, correct?
EDIT: in reply to Lasse V. Karlsen question:
$ git log --format="%h %d"
8059943 (HEAD -> master)
b63a44f
beb5d33
025f660 (origin/master, origin/HEAD)
1f16a0d
0bd94aa
1e9d375 (dizione_e_sede)
c19c33a
c2bc958
d1801c3
1dd9a87
e4f0846
2091d2e (origin/conv_pdf)
84076f3
[...]
$ git log --format="%h %d" origin/master..master
8059943 (HEAD -> master)
b63a44f
beb5d33
1f16a0d
0bd94aa
$
And on the server I see the following:
On hover on the red circled X a message "Pipeline: failed" appears.
I should also mention that we upgraded our gitlab server from a very old version to 14.4.1, right in the middle of these commits – may this be related?...
CodePudding user response:
Try using from CLI (command line):
git log --oneline --decorate --graph --all
or if you have a GUI (on windows or Linux or Mac):
gitk --all
This will allow you to see the history in a more visually appealing way. I believe this is what you're looking for.
CodePudding user response:
This is normal. The git status
command that shows that you are five commits ahead is correct (modulo bugs in Git, which are relatively rare). The git log
output you see is also correct, but contains a subtle kind of lie:
commit f4474af2add220b1c2f0bf07d92f5035cef622ef (HEAD -> notifiche, master) Author: Francesco Marchetti-Stasi <f.marchettistasi@***> Date: Fri Dec 10 14:55:48 2021 0100 [...] commit b63a44f7c1266a53a0e5c91a3395fc9eb75d9bd2 Author: Francesco Marchetti-Stasi <f.marchettistasi@***> Date: Tue Dec 7 16:46:59 2021 0100 [...] commit beb5d335e0ac35184b6a8e78bf45627e705a2a9b Merge: 1f16a0d 025f660
When git log
shows commits, it does so using a fairly complicated internal algorithm that uses a priority queue. This handles the fact that the commit graph is a DAG, not a simple tree. In particular merge commits result in tricky traversals.
Note that the third commit in the list here is in fact a merge commit, with two parents: 1f16a0d
(shortened) and 025f660
(also shortened).
The next commit that git log
shows you, in its linearized sequence, is:
commit 025f660ebc22b2d3bee00c691657c6e7318fcf50 (origin/master, origin/HEAD) Author: Francesco Marchetti-Stasi <f.marchettistasi@***> Date: Tue Dec 7 11:44:48 2021 0100
or 025f660
: this is the second parent of the merge. This is the commit that origin/master
names.
The commit that git log
shows after 025f660
is:
commit 1f16a0dcd96862b0ca75d3f3ca896ad755ccf29e Author: Francesco Marchetti-Stasi <f.marchettistasi@***> Date: Thu Nov 25 09:38:21 2021 0100
which is the first parent of that merge. The reason it gets shown after, rather than before, is that its time stamp (in late Nov) is earlier than the time stamp of 025f660
(7 Dec of the same year).
This is all clearer, in my opinion at least, if we draw a graph. Here's a partial graph of what you're seeing, where I have replaced each commit's big ugly hash ID with a simple o
or *
or ●
:
...--●--o--o---*--o--o <-- master
\ /
●-----● <-- origin/master
The commit marked *
is the merge commit. The commits whose hash ID has been replaced by a black circle ●
are on both branches; the other commits are only on master
. There are four open circles and the one starred merge, so there are five commits on master
that are not on origin/master
.
This graph can be drawn any number of ways:1 using git log --graph
, or git log --graph --oneline
, will make Git draw one for you, vertically oriented with the newest commit at the top. Because git log
outputs commits one at a time, any sequence that doesn't include the graph, but does include a merge commit, must necessarily be some kind of lie (of omission or commission, depending on what you'd prefer and how you view this) when it implies a simple linear chain of commits. That's because the merge commit ties together some otherwise separate-but-parallel chains. The log command must walk both sides of the chain, or omit one side of the chain, and whichever choice you tell it to make, the result will be either incomplete ("walk just the first-parent links") or incorrect-or-incomplete based on your viewpoint.
1Here's an alternative drawing that, I think, makes the situation clearer in most cases, though git log --graph
won't draw anything like this at all:
o--o
/ \
...--● *--o--o <-- master
\ /
●--● <-- origin/master
This is how I like to lay out my drawings where I show how git merge
works.
Optional reading: some further details
The git log
algorithm uses a priority queue.
The code begins by seeding the queue with one or more starting point commits (if there are no starting point commits, git log
does nothing, but the default is to use the HEAD
commit, and HEAD
almost always specifies a commit: the exception is when you are on a branch that does not exist, which Git calls an orphan branch or an unborn branch—Git is not consistent about which term it uses). That is:
git log
inserts the HEAD
commit (only) into the queue, while:
git log --branches
inserts all branch-tip commits into the queue, and:
git log master origin/master
inserts the commits identified by the names master
and origin/master
(this may be one single commit, if both names select the same commit, or two separate commits as in your case).
Because the queue is a priority queue, if it contains more than one entry, the "front" entry is the one with the highest priority. This is controlled by various options to git log
, such as --date-order
, --author-date-order
, or --topo-order
, but the default is to use the committer timestamp (which is not shown by default: the dates you see here are author dates; but fortunately most commits have the same author and committer date), with the latest timestamp—the most recent commit—having the highest priority.
If the queue has only one entry, of course, that one entry has the only priority, which is therefore the highest, average, and lowest priority all at the same time. So that's a degenerate case—but an important one since very often, there's only one entry in the queue. For instance, that's the case for your git log
, which inserts just the HEAD
commit, which is also the master
commit.
The log code now runs a loop:
- while the queue is not empty
- remove the front entry (a commit)
- decide whether to show this commit
- if so, show it (there's a special bit of weirdness with
--reverse
here though)
- if so, show it (there's a special bit of weirdness with
- decide which parent(s) if any to insert into the queue
The defaults for the two "decide" steps are: yes, do show it; insert all parents.
Most commits have just one parent, so for the first commit—identified by HEAD
and notifiche
and master
—the loop shows that one commit, "decorated" with the two branch names, and inserts its one parent b63a44f7c1266a53a0e5c91a3395fc9eb75d9bd2
.
The queue now has one commit in it, so the loop runs and shows the second commit. There are no names for that commit—no branch identifiers, no tags, etc.—so we just see that commit, without (origin/master)
or anything. The parent has one parent too, so that one parent goes into the queue: we're now at beb5d335e0ac35184b6a8e78bf45627e705a2a9b
, which is the merge commit.
The queue now has one commit in it, so the loop runs and shows the third commit. This commit has two parents, 1f16a0d
and 025f660
. They're both inserted into the priority queue.
Now we hit the priority code: the queue has two entries. One of them is at the front. The git log
code extracts that one. It's the second parent, but it's the higher priority because it has a later committer timestamp.
The git log
code now shows this commit, which is named by one name, origin/master
, so now you see the misleading output. That commit has one parent, which goes into the queue, which continues to have two elements in it.
This pattern repeats until the branching implied by going backwards through the merge is itself resolved. Once there's only one commit in the queue, we return to the normal single-threaded walk. (Using --topo-order
makes sure that this happens as soon as possible, and --graph
implies --topo-order
.)