4

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?

Daniel McIntosh
  • 522
  • 3
  • 17
Pedro Delfino
  • 2,421
  • 1
  • 15
  • 30
  • 1
    I think 1 or 2 are really the only common number of parents. While I think in theory any number is possible, I don't know of any workflows that creates >2 parents. Edit: [there are samples of it in the wild](https://softwareengineering.stackexchange.com/questions/314215/can-a-git-commit-have-more-than-2-parents). – Joachim Sauer Jul 16 '21 at 17:16

3 Answers3

8

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:

TTT
  • 22,611
  • 8
  • 63
  • 69
3

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.

Jeff Bowman
  • 90,959
  • 16
  • 217
  • 251
  • 2
    Consider also `git rev-list --no-walk --parents | wc -w` (though you then have to subtract 1 or otherwise fuss about with the output). – torek Jul 18 '21 at 05:02
3

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

Daniel McIntosh
  • 522
  • 3
  • 17
  • With Git 2.40.1, that `--skip=1 ` workaround doesn't seem to be necessary any longer; I also get a count of `0` on the root commit without it. – Ingo Karkat Apr 30 '23 at 18:37