Search code examples
gitbranch

Can I tell if the current commit is the first commit in a new branch


I'm trying to enforce commit message formatting. I would like for the first commit in a new branch to include the issue #/defect #. But subsequent commits in that branch don't need to. I was thinking that I could check if the parent commit had other children, or if the parent commit was part of other branches besides the current one.

And I need to do all this within the pre-commit hook. Any ideas?


Solution

  • What you've asked for is whether the current commit is the first commit in a new branch: that is, whether this commit is an orphan commit or the first commit in a repo. However, what it sounds like you want is to know whether your branch has diverged from the main branch (that is, it has commits that the main branch does not have), so I'm going to answer that. We'll assume that the main branch is main.

    If you're doing this in a pre-commit hook, then you're interested in whether the commit you're going to be creating is the first new commit on the branch. Since the current branch has no additional commits diverging from the main branch, we can write this, which will exit 0 if this is the first divergent commit on the main branch and 1 otherwise:

    $ [ "$(git merge-base main HEAD)" = "$(git rev-parse HEAD)" ]
    

    That asks whether the merge base (in this case, the most recent common commit) is the same as the current branch.

    Now, pre-commit hooks are great for helping developers, but since you're trying to enforce policy, they're not a good choice for that. From the Git FAQ:

    The only safe place to make these changes is on the remote repository (i.e., the Git server), usually in the pre-receive hook or in a continuous integration (CI) system. These are the [only] locations in which policy can be enforced effectively.

    The FAQ entry explains why in more detail.

    So, since you're going to be running this in a CI system in all likelihood, things will be a bit different. What you'll want to know is which commit is the first divergent commit in a branch, which we can answer like this:

    $ git rev-list main.. | tail -n1
    

    That determines the ID of the first commit in the current branch which is not in main.