Amanite Laurine
Amanite Laurine

Reputation: 1149

Show all branchs history with child branchs

I am searching for a way to visualize all branch in remote (with git) in a single time, like on this image, even if some branchs don't have any commit. enter image description here

But when I run gitk command, I obtain something like this :

enter image description here

On this image, it looks like master is child of dev, and the feature branchs are on the same level, and if master had no commit, it would have look like if master and dev are same the branch.

Is there a way to display the branchs history in a clearer way like on the schema ? All the solutions I have found give the same result as the gitk.

Upvotes: 1

Views: 241

Answers (1)

Mark Adelsberger
Mark Adelsberger

Reputation: 45659

UPDATE - A few notes added at the end, as comments suggest a bit more information might help.


The problem is that you're trying to impose concepts on git that don't exist in git.

There is no such thing as a "branch with no commits". A commit doesn't "belong to a branch". A branch is not a "child" of another branch. No tool can look at a repository and, based on the information there, draw an intuitive graph aligned with these concepts, because these concepts are not to be found in the information kept in a repo.

In git a branch is a type of ref. A ref is a pointer to a commit.

When you say "branch with no commits", you mean "someone was on branch a and created a new branch b; but nobody has yet committed while on branch b". git doesn't know that's what happened; what git knows is that the branch ref for b points to a commit that's reachable from a. In many cases that means b and a point to the same commit.

The type of diagram you want is drawn with the notion that every commit can be uniquely assigned to a branch. In git a commit is either reachable from, or not reachable from, any given ref. (Reachable means that you can find the commit by first looking at the commit the ref points to, and then possibly following the parent pointers on commits.) A commit can therefore be reachable from many branches at the same time. Often the "root" commit is reachable from all branches. If you are on branch a and you create branch b, then all the commits reachable from branch a are also reachable from branch b.

When you think of a branch b as a "child" of another branch a, you mean that someone was on a when they created b. This is not something git keeps track of. It is impossible to tell whether a was created from b, or b was created from a, or both a and b were created from some other branch.

If you strictly follow a set of conventions for how you branch and merge, then you could conceivably create a tool that interprets the branch/commit topology assuming those conventions to produce something like you want. How useful this is may depend on how realistic it is to think that you'd never have to violate your conventions. I don't know of any such tools, and since they would work in terms of fictitious concepts that don't matter to git I'm not sure how useful it would be in practice anyway.

The sample diagram you have comes form a document describing a particular branching practice. That practice imposes some of the concepts (like child branches), so it makes sense to describe the ideal of that practice using that type of chart. But in a real repo, that's just not how things look.

UPDATE STARTS HERE

In comments you mention that you can't tell what branch a given commit was made on. In general this is correct, because that is not a thing that is tracked in git. You can tell from what branch(es) a commit is reachable, because that's all git knows - and sometimes that allows you to infer what branch it was created on.

But you mention not seeing separation between the branches, and that got me thinking. In your gitk diagram there just isn't much separation between the branches. And probably that's caused by the use of "fast-forward" merges, which - for better or worse - is a default behavior of git even though it can be very confusing.

Suppose I start working in a repo that has a single commit, and master and dev branches.

X <--(master)(dev)

Now, I start working on the dev branch. I create a few commits.

X <--(master)
 \
  A -- B -- C <--(dev)

Now, I merge to master. By default git sees that it can take a shortcut, by just updating the master ref to point at C. This is called a fast-forward.

X -- A -- B -- C <--(dev)(master)

If we think only about the content that's "current" on master, this shortcut got us the correct result. But some facts about history are lost. We can prevent this if, instead of just saying git merge dev, we say

git merge --no-ff dev

If you're using a branch strategy that gives meaning to the branch topology, you almost always should use --no-ff when merging. This would yield

X ----------- M<--(master)
 \           /
  A -- B -- C <--(dev)

and the graph you'd see in gitk will probably be more agreeable to you (though it still won't look quite like what you see in the diagrams you refer to).

Upvotes: 2

Related Questions