Where does a Git branch start and what is its length?

In Git, you could say that every branch starts at the root commit, and that would be quite literally true. But I guess that’s not very helpful for you. What you could do instead is to define “the start of a branch” in relation to other branches. One way you can do this is to use

git show-branch branch1 branch2 ... branchN

and that will show you the common commit between all specified branches at the bottom of the output (if there is, in fact, a common commit).

Here’s an example from the Linux Kernel Git documentation for show-branch

$ git show-branch master fixes mhf
* [master] Add 'git show-branch'.
 ! [fixes] Introduce "reset type" flag to "git reset"
  ! [mhf] Allow "+remote:local" refspec to cause --force when fetching.
---
  + [mhf] Allow "+remote:local" refspec to cause --force when fetching.
  + [mhf~1] Use git-octopus when pulling more than one heads.
 +  [fixes] Introduce "reset type" flag to "git reset"
  + [mhf~2] "git fetch --force".
  + [mhf~3] Use .git/remote/origin, not .git/branches/origin.
  + [mhf~4] Make "git pull" and "git fetch" default to origin
  + [mhf~5] Infamous 'octopus merge'
  + [mhf~6] Retire git-parse-remote.
  + [mhf~7] Multi-head fetch.
  + [mhf~8] Start adding the $GIT_DIR/remotes/ support.
*++ [master] Add 'git show-branch'.

In that example, master is being compared with the fixes and mhf branches. Think of this output as a table, with each branch represented by its own column, and each commit getting its own row. Branches that contain a commit will have a + or - show up in their column in the row for that commit.

At the very bottom of the output, you’ll see that all 3 branches share a common ancestor commit, and that it is in fact the head commit of master:

*++ [master] Add 'git show-branch'.

This means that both fixes and mhf were branched off of that commit in master.

Alternative solutions

Of course that’s only 1 possible way to determine a common base commit in Git. Other ways include git merge-base to find common ancestors, and git log --all --decorate --graph --oneline or gitk --all to visualize the branches and see where they diverge (though if there are a lot of commits that becomes difficult very quickly).

Other questions from original poster

As for these questions you had:

Is commit D a member of both branches or can we clearly decide whether it belongs to branch-A or branch-B?

D is a member of both branches, it’s an ancestor commit for both of them.

Supervisors sometimes like to know, when a branch has been started (it usually marks the start of a task)

In Git, you can rewrite the history of the entire commit tree(s) and their branches, so when a branch “starts” is not as set in stone as in something like TFS or SVN. You can rebase branches onto any point in time in a Git tree, even putting it before the root commit! Therefore, you can use it to “start” a task at any point in time in the tree that you want.

This is a common use case for git rebase, to sync branches up with the latest changes from an upstream branch, to push them “forward” in time along the commit graph, as if you had “just started” working on the branch, even though you’ve actually been working on it for a while. You could even push branches back in time along the commit graph, if you wanted to (though you might have to resolve a lot of conflicts, depending on the branch contents…or maybe you won’t). You could even insert or delete a branch from right in the middle of your development history (though doing so would probably change the commit shas of a lot of commits). Rewriting history is one of the primary features of Git that makes it so powerful and flexible.

This is why commits come with both an authored date (when the commit was originally authored), and a committed date (when the commit was last committed to the commit tree). You can think of them as analogous to create time-date and last-modified time-date.

Supervisors sometimes like to know…to which branch some changes belong to (to get the purpose of some change – was it required for the work).

Again, because Git allows you to rewrite history, you can (re)base a set of changes on pretty much any branch/commit in the commit graph that you want. git rebase literally allows you to move your entire branch around freely (though you might need to resolve conflicts as you go, depending on where you move the branch to and what it contains).

That being said, one of the tools you can use in Git to determine which branches or tags contains a set of changes is the --contains:

# Which branches contains commit X?
git branch --all --contains X

# Which tags contains commit X?
git tag --contains X

Leave a Comment