Re: git bug: Including a git repository in a directory
Hi!
René Scharfe <l.s.r@web.de> writes:
Show 22 quoted lines
> Am 06.06.22 um 07:43 schrieb Steven Jonn Edlefsen:
>> Git cannot commit/push a directory with a git repository in
>> a sub-directory.
>>
>> The sub-directory with the git repository and the directories below
>> are set to the “master” branch, while the directories above remain
>> set to the new branch.
>>
>> When the top directory is committed, the sub-directory with the
>> git repository appears as an empty file.
>>
>> Even when the subdirectory branch name is changed from master
>> to the new branch and the top directory is re-commited/pushed,
>> the same problem occurs.
>>
>> When the git repository in the sub-directory is removed, e.g.
>> the .git file is removed, and top directory is committed/pushed,
>> the subdirectory has all the sub-directories and files.
>
> This is intended behavior. A repository inside another one needs
> special handling. Git provides the submodule feature for that. A
> simpler alternative for some use cases is called subtree.
As René described, this is intended behavior - repositories cannot contain entire repositories with `.git` inside them [1]. As far as I know, this is security feature because `.git` can contain sensitive files that you wouldn't want to clone down, e.g. .git/config can make "git" execute arbitrary code.
What happened in your case is that Git noticed that the subdirectory is a repository and automatically 'sanitizes' it for you by converting it into (what is essentially) a submodule [2]. When a subdirectory is a submodule, Git stores a single commit id for the entire subdirectory - you you can no longer change individual files inside the subdirectory.
To demonstrate this "single commit id" behavior, this is what happens if you tried to `git init` a subdirectory in an existing project:
$ git init foo
Initialized empty Git repository in /Users/chooglen/Code/repo/foo/.git/
$ git add foo
error: 'foo/' does not have a commit checked out
Notice the line above! We can't add `foo` because it has been converted into a (pseudo) submodule [2].
$ (cd foo && git commit -m "foo" --allow-empty) # create a commit
[main (root-commit) 9e27581] foo
$ git add foo
warning: adding embedded git repository: foo
hint: You've added another git repository inside your current repository.
hint: Clones of the outer repository will not contain the contents of
hint: the embedded repository and will not know how to obtain it.
hint: If you meant to add a submodule, use:
hint:
hint: git submodule add <url> foo
hint:
hint: If you added this path by mistake, you can remove it from the
hint: index with:
hint:
hint: git rm --cached foo
hint:
hint: See "git help submodule" for more information.
$ git diff HEAD
diff --git a/foo b/foo
new file mode 160000
index 0000000..9e27581
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+Subproject commit 9e27581b9eb91c0f1699eb18a2e81d758de9209d
Now that there is a commit in the subdirectory repository we can `git add` it, but only as an entire commit. We cannot just add individual files.
If you truly need a repository inside of another repository. You may want to consider submodules/subtrees as René mentioned.
[1] A repository can contain a "bare" repository because a bare repository does not have `.git`, but that isn`t relevant to the discussion here. [2] A submodule technically also has to have an entry in the .gitmodules file.