This is just an expansion of Schwern's answer, which is correct—but you may need to add a git rm -r
of all files, and maybe a git clean
as well. There is also one corner case where you can do nothing at all, and maybe you don't really want to remove files.
Long
There are several possible answers to this, depending on what you're really looking for. Let's start with some background and definitions:
A new, totally empty repository has no commits. A branch name can only exist if it identifies a commit and with no commits there are none to identify. So this repository has no branches. Curiously, you're still on a branch. It's just that the branch that you are on does not exist.
In this kind of repository you have only one option, which is be on an "orphan branch". We'll come back to this in a moment.
Otherwise—when there are commits—you can have any number of valid, existing branch names, each of which must point to some existing, valid commit. You can be on exactly one of these branch names, or you can be in detached HEAD mode, or you can use the "orphan branch" mode.
The orphan branch mode is the oddest of the three, but let's describe it first, then the other two:
Orphan mode: HEAD
contains a branch name. This is the current branch, so you are on a branch. The odd part is that the branch you are on does not exist. A git branch
command will list the branch names that do exist, but not the branch name that you are on, because it does not exist.
Normal mode: HEAD
contains a branch name. That is the current branch, and the commit hash ID stored in that branch name is the current commit.
Detached-HEAD mode: HEAD
contains a commit hash ID. That is the current commit; there is no current branch.
A git clone
normally results in normal mode. The branch name that becomes the current branch is the one you select at git clone
time, with your -b
option. There are some exceptions to this rule, though: if your -b
names a tag, Git will check out that tag, putting you in detached-HEAD mode. If you don't specify a -b
option, your Git asks the other Git what branch name they recommend, and uses that name, or a fallback name; if that name or the fallback name fail to name a branch, you wind up in orphan mode, with a nonexistent branch as the current branch. If you do specify a -b
option, the name must name an existing branch or tag in the other Git repository, otherwise the clone command as a whole fails.
The -n
option has no effect on the mode of the new clone. You are in normal, detached-HEAD, or orphan mode exactly as you would be without it. The only effect the -n
option has is that it prevents the initial git checkout
. The branch name is still created locally, when using normal mode, so that if there are branches in the repository you've cloned, you will be on one of them, with that branch name existing locally and pointing to the same commit as the remote-tracking name. This is a weird special case that I'd argue is a minor bug, since if you ran git init
, git remote add
, and git fetch
without doing a git checkout
you'd be left in orphan mode instead. (It's the git checkout
step that creates the branch, when using commands other than git clone
itself, so skipping it should leave you in orphan mode. But it doesn't.)
Git's index and your working tree
The above is all about HEAD
—what's stored in it, and which branch and/or commit is current, if any—and branch names. But when we look around in a non-bare repository, we see a bunch of files, stored as ordinary everyday files. These files are not what is in Git. What is in Git are the branch and tag and other names—as a sort of secondary database—and also a series of commits and supporting objects, stored in the primary (and usually much larger) database.
The commits function as archives and as history. Each commit stores a full snapshot of every file, as if in a tar or rar or zip archive. Each commit also stores some metadata, including the name of the person who made the commit, and so on. Everything in these archives is strictly, totally read-only: inherently so, because it's all addressed by numbers produced via a cryptographically-strong hash function. Any attempt to change any stored data results in incorrect hash values,1 which Git detects, and reports as a corrupted repository.
But with no ability to change these files—or even view them, in most programs—these archives would be useless. So Git will extract an archive into a working tree: an area where you can see and use your files. This is—at least initially—what you have in your working tree: the result of extracting some commit. The commit that is extracted is the current commit.
Technically, this is all we need: the commits as archives-and-history, and a working copy. When we consider these as "the current commit" and "the working tree copy", that's two copies. Those are all there are in some version control systems. But for whatever reasons, Git inserts a third copy of each file, in between the frozen-for-all-time current-commit copy and the readable, writable, useful version in your working tree. This makes the working tree copy become the third copy, as it were: the second copy of each file exists in Git's index.
The format of the files in Git's index is that of files in commits: they're pre-compressed and pre-de-duplicated. The files in the commit archives are all de-duplicated, which generally saves tons of space. One trick that Git uses to go fast here is that the index copies are pre-de-duplicated, so that there's no work needed at commit time. What this means here is that the index copies of files take almost no space. For instance, the expanded-out files for the Git project for Git occupy about 57 MiB on one of my machines here, but the index needed to hold those same files is only 368790 bytes. (Note: neither of these numbers counts the .git
directory.) But in principle there are three copies of the commit: HEAD
—the commit itself—plus the index plus the working tree copy.
1Unless, that is, you can spend enough compute time to produce hash collisions. See How does the newly found SHA-1 collision affect Git? Note that this does not happen by accident, and it's impractical for most groups to do it even on purpose today (though it's no longer beyond the abilities of large companies like Google, nor various nation-states).
How all this relates to git clone -n
When you use git clone -n
, you get one of the three modes for HEAD
: orphan branch, detached HEAD, or normal. But Git does not run git checkout
, and it's git checkout
that fills in Git's index and your working tree. So you have a nominally-empty index and working tree.2
Hence, if you wish to reproduce this condition exactly, you will need to:
- determine what kind of
HEAD
setup to use; and
- empty out the index and working tree.
For simplicity in part 1, you can simply assume normal mode and do nothing. For simplicity in part 2, you can use git read-tree --empty
, which erases the index, followed by git clean
with various options. You can use git read-tree --empty -u
to remove all indexed files, leaving only untracked files behind in the working tree. Or you can choose to leave the working tree alone.
If you wish to reproduce a detached HEAD (complicating part 1 a bit), you have two choices:
- run
git checkout --detach
or git checkout
of anything that is not a branch name, or
- with Git 2.23 or later, run
git switch --detach
with any commit specifier.
The specified commit (or the HEAD
commit, when using git checkout --detach
with no arguments) becomes the current commit and you are now in detached-HEAD mode. The commit you check out here (or switch to with git switch
) will fill Git's index and update files in your working tree, except for the special cases outlined in Checkout another branch when there are uncommitted changes on the current branch.
To get into orphan mode, use either git checkout --orphan
or git switch --orphan
. Be aware of this sneaky incompatibility: the old checkout method leaves Git's index and your working tree undisturbed. The git switch
command empties the index and cleans up your working tree as if with git read-tree --empty -u
.
(In all cases, untracked files are undisturbed, whether or not those untracked files are also ignored.)
2An empty index is a non-zero-length file as the index has headers and trailers. These contain cryptographic hashes, so as to detect on-disk corruption, just as the repository object database does. To make this work conveniently, Git treats a non-existent index as "empty", and creates the empty index in memory, and will write it with correct checksums once it becomes appropriate to do so.
The top level of the working tree normally contains the .git
directory that is the repository proper, so that an "empty" working tree is never quite empty. You can, however, split the repository and working tree directories apart with various options.
Final notes and conclusion
Whatever mode you go into, note that running git commit
will now try to create a new commit as usual:
In orphan mode, this will create a new commit with no parent (a new root commit) and create the branch whose name is in HEAD
. The branch now exists, and holds one root commit, not connected to any other commit via the commit graph.
(It's probably a bad idea to do this while concluding a merge. I don't know what happens if you try this.)
In detached-HEAD mode, this will create a commit with the usual parent (the current commit as parent, plus any additional commits from an in-progress merge). Git will then store the new commit's hash ID in HEAD
, which continues to be detached, but now points to a commit that can only be found via HEAD
.
In normal mode, this will create a new commit as usual (including concluding a merge as usual, just like with the detached-HEAD mode), and then store the new commit's hash ID in the branch name stored in HEAD
.
The new commit will store, as its snapshot, whatever files are in Git's index. If you emptied the index, that's an empty tree. If you left or put files in the index, those are the files in the snapshot.
There's likely no real reason to do any of this, but the safest of these various modes is probably the new-orphan-branch mode with an empty index and empty working tree. That way, no one will accidentally git commit
a new empty tree on some existing branch. The simplest of these is probably the detached-HEAD mode; this way, you can clean out the index and working tree, or not, without too much concern.