Understanding ordering of the timeline of Git commits

636 views Asked by At

Please consider helping me to understand the timeline. In one tutorial the timeline arrows are pointing right to left.

That is Commit 7 points back to Commits 6 which points back to Commit 5, etc. This makes sense if commits are in an array and you keep adding commits to the front of the array. However, it's not how one (I) usually thinks of timelines.

In another the timeline arrows are pointing left to right (which is how I normally think of a timeline.) The original Commit 1 points to the next changed Commit (2), etc.

Which is the right way to think of Git timelines?

2

There are 2 answers

0
kostix On

Please note that tutorials (at least those I've seen) do not discuss timelines, instead, they discuss commit graphs.

The basic idea is that each commit except for the very first commit in a branch has one or more parent commits. Naturally, these parent/child relations form a graph with commits being its vertices and those relations being its edges.

Tutorials usually render those edges using arrows. Where those arrows point (from a child to its parent(s) or vice-versa) supposedly depends on what the author of a particular visualization tried to convey: if they wanted to convey parent/child relations, the arrows will supposedly be pointing at parents, and if they wanted to highlight "the direction of the development progression" the arrows will supposedly be pointing at children.


Please consider unlearning this concept of "the timeline" as soon as possible — otherwise this might bite you later.

The problem with it is that it simply does not exist in Git. Yes, what git log shows to you appears to form a timeline but this is deceiving because as of yet you're dealing with the simplest case where the parent/child relations of commits in your history progress linearly along the imaginary timeline.

Now suppose this simple case:

  1. You have a branch "A" on which you've created, say, ten commits.
  2. Then you fork a branch "B" off it and start implementing some feature on that branch.
  3. While hacking on "B", you continue to add stuff on "A" from time to time. Suppose you've managed to add another ten commits on "A" while hacking on "B".
  4. Now the feature that was being cooked on "B" is complete so you merge "B" back into "A". Let's suppose you have done twenty commits on "B" before merging it back. The result will be a "diamond" in your history graph: the histories diverge and then converge back again — forming "the sides" of the diamond. One side of it — that of the "A" branch — will have ten commits, and another one — of "B" — will have twenty. Starting from the merge commit, you'll have just a single line of commits again.

As you can see, you don't have a simple and easy timeline anymore because in the middle of it will be a diamond formed by the two "sub timelines" :-)

Sure, there Git tools which show you the history by default will happily "fold" both sides of that diamond into something which looks like a single timeline but the ordering of those commits will not reflect their parent/child relation.

Hence the sooner you change your mental model of the history in a Git repository to adopt that graph concept the better you're prepared for dealing with real repositories which have lots of merges.

0
David Deutsch On

Technically, the correct way is the first way, i.e. arrows pointing backwards in time. This is because of the way git commits are actually stored: each commit has a pointer back to its parent.

All that being said, you will often see it done both ways. Use context to determine which one is being used.