git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git bug: Including a git repository in a directory

From
Glen Choo <chooglen@google.com>
Date
Jun 6, 2022, 16:57 UTC
Message-ID
<kl6ly1y9d91t.fsf@chooglen-macbookpro.roam.corp.google.com>
In-Reply-To
<24022c08-ed58-8157-6036-6a4c6a49f195@web.de>
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.

Previous: René Scharfe
Message 3 of 3 in “git bug: Including a git repository in a directory”
  1. Steven Jonn EdlefsenJun 6, 2022
  2. René ScharfeJun 6, 2022
  3. Glen ChooJun 6, 2022

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.