Rebse
Rebse

Reputation: 10377

Git operations on repository without a working tree?

The build workflow of a legacy project should checkout a specific git version tag and compile that sources. I proposed to keep it simple and use Git Cli like that:

git clone –b $versiontag –singlebranch $gitrepouri

instead of git clone and git checkout tag afterwards.

To "save time", a colleague wants to use another approach = copy the .git folder from an existing Git repository at another server to the build working dir and afterwards operate on that folder.

At first she tried with git checkout $versiontag after the copy.
The output has multiple entries like:

$ git checkout tags/sometag
D       Foobar/somefile
D       Foobar/someotherfile
[...]
Note: checking out 'tags/sometag'.

You are in 'detached HEAD' state.
[...]

but the working tree content differs from a normal git clone and git checkout, though both suppose to be in the detached head state and have checked out that specific tag.
Also there were problems with tools like Sonarqube, because git blame didn't work
(Missing blame information..).

Afterwards she tried with git sparse-checkout after the copy, and that seems to work
at first sight - though it's much more complicated and complex compared to the simple Git Cli approach.

What are the drawbacks of using Git commands against a Git repository without working tree overall ?

Upvotes: 0

Views: 1690

Answers (1)

torek
torek

Reputation: 488163

Git has an internal setting to tell itself that it's using a clone with no work-tree. Specifically, core.bare should be set to true for such a repository.

Copying a repository manually, rather than using git clone to copy it, copies its configuration files (.git/config and .git/info/ files). This includes the core.bare setting and several settings that Git creates on its own to describe the behavior of the machine and file-system on which Git is running. If these settings do not reflect the actual machine and actual file system, things may go wrong in various ways. Some of the info files may point Git into additional directories not copied; if so, you need to know what to do about these as well. So, unless you know what you are doing with respect to these other variables and info files, do not use cp -r (or tar or similar) to copy the .git directory directly.

Copying the raw .git repository also copies the index for that repository. The index describes the work-tree, so the copied index is automatically incorrect if the new location has no work-tree. (Note: all repositories, including bare ones, have an index. The index for an initially-bare repository is normally empty, but see below.)

That said, you can do some Git operations on a bare repository. Specifically, you can do any operation that does not require a work-tree. This means that if you know what you are doing with respect to the special control variables, you can copy a .git repository elsewhere and then use it. Since you will be avoiding operations that use the work-tree—which means avoiding git checkout, for instance—the broken index is not a problem, although if you're going to be this clever, which is perhaps too clever by half, you can also just know when it is safe to remove the broken index.

You can also supply a temporary work-tree for a bare repository, using git --work-tree=<path> ... or GIT_WORK_TREE=<path> git .... If you do this, that overrides the core.bare setting, and the bare repository's index is used to keep track of the given <path>. Note that if you change paths, you invalidate the index; in this case, you must either use another index (by setting GIT_INDEX_FILE to an alternate index) or remove the existing index.

So, with all the above caveats in mind, you can convert a .git directory to a proper bare Git repository, or use cp or tar to transplant a .git directory including or excluding its current work-tree to a new location with a new work-tree. But in general, you shouldn't, because if you do this, you must make a lot of assumptions about future versions of Git. Git promises that git clone and git bundle and the like will keep working the way it does now; Git does not promise that sneaky surgery on a copied .git directory will keep working this same way.

Upvotes: 2

Related Questions