27

I am writing a custom git command that should only run in a completely new repository with no commits (see this question). How can I perform a simple check within my script to see if an existing repo has zero commits?

Essentially, what goes in the blank below?

if ___________ ; then echo "Git repo already has commits. Aborting. else echo "Git repo has no commits. Doing whatever my script does." fi 
1
  • Note that error message should always go to stderr: echo "Git repo already has commits. Aborting." >&2 Commented Aug 4, 2023 at 10:17

2 Answers 2

40

Summary:

  • A commit is checked out: test git rev-parse HEAD 1>/dev/null 2>&1
  • A ref pointing to a commit exists: test git rev-list -n 1 --all 1>/dev/null 2>&1
  • Objects exist in the repo: test output of git fsck, git count-objects, or the examine the contents of .git/objects

And now for the discussion!

If you want to know whether a commit is checked out, you can use git rev-parse HEAD. There will be output, so you probably want to redirect to /dev/null and just use the exit code. For all practical purposes, this will be good enough - doing normal things, it's pretty much impossible to end up without HEAD pointing at anything. But it is possible, for example by deleting files in the .git directory. Depending on your script, this might be important - if you're about to blow away the .git directory, you want to be paranoid indeed.

If you want to see whether there are any refs at all with commits on them, you can use git rev-list -n 1 --all. Again, there will be output (the SHA1 of the first commit encountered), so redirect to /dev/null and check the exit code.

Finally, if you want to check if there are any commits - even if they aren't on any refs (you have to try really hard to get into this state) I'd probably just check for the presence of objects with git fsck or git count-objects - or failing that, list .git/objects and check for anything besides info and pack (commands tend to fail if there is no file .git/HEAD). And yes, you could actually have a repo with blobs and trees but no commits, but you'd have to try even harder to get there. These are the absolute safest methods, if your script is scary.

Sign up to request clarification or add additional context in comments.

8 Comments

Since we're dealing with this currently, I thought I might note that the git rev-parse HEAD is sensitive to the case where there's no "master" branch. git init --bare at least on my end creates a repo with HEAD pointing at master; but someone may come along and push commits to some other branch name and the script will not detect them (unless a hook updates HEAD or something). This seems like a pretty typical case worth noting in the answer.
beware that git fsck is not readonly or could take a long time, and that git count-objects will report ZERO if there is only a pack. You can try git count-objects -v to also see how many objects are in the packs.
@ingyhere When the answer says "a commit is checked out", it does not mean "a branch is not checked out". If you have a branch checked out, that branch is pointing to a commit, and git rev-parse HEAD will succeed. If you have nothing whatsoever checked out, as when you've run git init but not yet committed, then it will fail.
git rev-list -n1 --all always exits with exit code 0, no matter whether there are any refs or not. Using test -n "$(git rev-list -n1 --all)" works fine for me though.
nit: These work in bash (and probably some other shells). However, in some shells (notably dash) 'git rev-parse HEAD &> /dev/null' will run git rev-parse in the background and then perform a no-op truncating /dev/null. IOW, &> is a non-portable shell construct (aka, a bashism) that should not be provided in an answer that is not specific to a particular shell.
|
4

You want to use git log

If you are using cygwin or are on a linux machine gitk is a useful program to have as well.

4 Comments

git log returns an error if there are no commits. Are you saying I should interpret a non-zero return value as a indication that the repo has no commits?
correct, git log will give you an error saying there is no 'HEAD' which means nothing exists. Also if you use git branch -l you will get no result (and no error) as well. If a commit existed a branch would exist as well (can't have one without the other).
Though that's true in normal usage, you could certainly manage to blow away all your branches (and still have commits) if you wanted to - or if you made some particularly unfortunate shell mistake.
[[ "$( git log --oneline -5 2>/dev/null | wc -l )" -eq 0 ]] && echo -n "no commits on this branch"

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.