Is it possible to count the number of parents a specific commit has?

Viewed 304

Most commits have 1 parent commit. However, some commits have multiple parents. For instance, merge commits that were created under the --no-ff (no fast-forward) flag have at least 2 parents.

Is there a command in git that shows the exact number of parents a specific commit has?

3 Answers

To view the list of parent commits:

git show -s --format=%p [commit-id]

To just show the number of parents:

git show -s --format=%p [commit-id] | wc -w

Explanation:

For a casual or human-readable answer, use git show as in TTT's post.

However, despite the clean use of --format, the output of git show is allowed to change: it is a "porcelain command" in git's "plumbing/porcelain separation". (The same is true of git log --format.) Changes might be unlikely, but you might also see errors and other human-directed output as git show is intended for human consumption rather than script consumption.

For a more rigorous or spec-guaranteed list of parents, suitable for long-lived shell scripts or tool integration, you'll want to use a plumbing command like git cat-file, similar to extracting a commit date without git log.

git cat-file -p [commit-id] | sed -ne '/^$/q;/^parent/p' | wc -l
  • git cat-file -p will pretty-print the object with the given ID. Revisions like HEAD also work here.
  • sed here will both filter and truncate the output:
    • -n suppresses all output.
    • -e uses a script specified on the command line.
    • /^$/q tells sed to quit if it sees a blank line, like the one separating commit metadata from its message. This prevents misinterpreting the word "parent" in your commit body text.
    • ; separates sed commands.
    • /^parent/p tells sed to print only the lines that start with parent, overriding -n.
  • wc -l prints the number of resulting lines.

Once again, for most cases git show is a more idiomatic way of doing this, since it reads and parses the commit all in one command and has already been written with edge-cases and oddities in mind. However, for developers of long-lived git tools, plumbing commands might be a more guaranteed solution.

To programmatically count the number of parents without using any pipes, you can use

git rev-list --no-walk --count --skip=1 <commit> <commit>^@

If you know that <commit> has a non-zero number of parents (i.e. it's not a root commit), this can be simplified to

git rev-list --no-walk --count <commit>^@

Explanation:

  • git rev-list --no-walk will interpret and print a list of all the revisions you give it (effectively the same as git rev-parse)
  • --count tells rev-list that instead of printing the list, it should print a count of the number of revisions
  • If <commit> has no parents, then <commit>^@ doesn't specify any revisions, so git rev-list will print its usage message (just like if we ran it with no arguments). To circumvent this, we pass --skip=1 and an extra revision for it to skip over (in this case <commit>).

credit to @jthill's comment here for the idea to use rev-list --no-walk --count

P.S. rev-list is also a plumbing command, so doesn't have the problems @Jeff Bowman pointed out in his answer

Related