user27665 user27665 - 8 days ago 4
Git Question

confusing git log results

To get the git branch hierarchy, I issue the following command to my git repo:

git log --all --graph --decorate --oneline --simplify-by-decoration


However, I get a confusing result:

* 023448b (I) Comments
| * 7b08b45 (H) Comments
|/
| * 379334c (G) Comments
| * ec95b66 (F) Comments
|/
| * dca9a7b (E) Comments
|/
| * f7bb48a (D) Comments
|/
| * 82224b2 (C) Comments
|/
* c7887dd (HEAD, master, A, B) Commments
* 5046cbf Initial Commit: Comments


The last but one line shows three branches. Isn't it supposed to show only the
master
? Also what is the meaning of the last sentence?

Answer

I don't know what you mean by "the last sentence", but:

Isnt it supposed to show only the Master?

No. You said --all. All means all: all branches, all tags, and all other references as well. If you only wanted to look at branch master you should have said master.

The way git log finds commits to show is to start from some set of references and then examine each commit those references point-to, then look at those commits' parent commits, then look at the parents' parents, and so on. This "walk" through history—looking at each commit's parent or parents, and queuing those commits for further examination—simply starts from the specified points, and continues until there are no more commits. Commits "run out" whenever this process reaches a root commit, which is a commit with no parents.1

The default for git log is to start from the name HEAD, unless you name some other starting point(s). You did that: you said --all, which means all starting points (except reflogs).

Meanwhile:

--simplify-by-decoration

directs git log to skip commits that do not have some branch or tag name pointing to them. However, for whatever reason, this never2 skips a root commit. And:

--decorate

directs git log to put the names of any branches and/or tags that point to that commit, on any commits shown (which of course are those retained by --simplify-by-decoration, except for root commits). Hence if you replace --all with master, you should expect to see:

* c7887dd (HEAD, master, A, B) Commments
* 5046cbf Initial Commit: Comments

since the names HEAD, master, A, and B all point to c7887dd (which is retained because a name points to it), and 5046cbf is a root commit (which is retained because it is a root commit).


1Note that this only stops adding more commits to the queue of "commits to examine". If the queue already has many queued commits, the process goes on to examine those. If there are multiple root commits in the graph, this process may find several or all of them (depending on where you start the traversal).

Both git log and git rev-list do breadth-first traversal of commit nodes within the graph, but both also sort the commits. Adding --graph forces the sort to use a topology-respecting order, in which no parent commit is shown until all its children have been shown (when working in the normal "backwards" direction, that is).

2A cursory re-check of the source code suggests that this is not quite true: root commits will be discarded if they have an empty tree attached. This check happens after modifying the attached tree based on any pathspec arguments given to git log or git rev-list, so you won't see root commits when looking for commits that modified some particular file. In this case there are no pathspecs, so you will only not-see the root commit if it is literally empty (refers to the empty tree).