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

git-submodule path computation bug with recursive submodules

From
BHBob Halley <halley@play-bow.org>
Date
Jul 5, 2012, 12:09 UTC
Message-ID
<0B4C40CC-862E-4B15-9A4F-903DC8DBBAEC@play-bow.org>

The git-submodule command has problems in some cases when there is a symlink in the path returned by pwd.

I've created a repository at http://www.play-bow.org/repos/product to demonstrate the issue.

$ git --version git version 1.7.11.1.116.g8228a23

I copied and built the head of the master branch today.

First we need a symlink. I discovered this problem because I had a symlink in / to a directory under my home directory for typing convenience.

$ ls -al /bug lrwxr-xr-x 1 root admin 17 5 Jul 12:26 /bug@ -> /Users/halley/bug

$ cd /bug $ pwd /bug

Note that pwd does not resolve the symlink (though pwd -P would on many platforms)

$ pwd -P /Users/halley/bug/product

$ git clone http://www.play-bow.org/repos/product Cloning into 'product'...

I'm purposely not using 'clone --recursive' as the bug doesn't appear if you do that.

$ cd product/ $ ls file1 file2 foo/

Let's get those submodules...

$ git submodule update --init --recursive Submodule 'foo' (http://www.play-bow.org/repos/foo) registered for path 'foo' Cloning into 'foo'... Submodule path 'foo': checked out '2b02e1eb2e34961d807cfc5fc7e477e0ca844600' Submodule 'bar' (http://www.play-bow.org/repos/bar) registered for path 'bar' Cloning into 'bar'... fatal: Not a git repository: ../../../../Users/halley/bug/product/.git/modules/foo/modules/bar Failed to recurse into submodule path 'foo'

The first level of submodule clones successfully, but submodule 'foo' contains submodule 'bar', and cloning it fails.

Now we'll try it again, but this time we'll take the symlink out of the picture.

$ cd /Users/halley/bug $ rm -rf product $ pwd /Users/halley/bug $ git clone http://www.play-bow.org/repos/product Cloning into 'product'... $ cd product $ git submodule update --init --recursive Submodule 'foo' (http://www.play-bow.org/repos/foo) registered for path 'foo' Cloning into 'foo'... Submodule path 'foo': checked out '2b02e1eb2e34961d807cfc5fc7e477e0ca844600' Submodule 'bar' (http://www.play-bow.org/repos/bar) registered for path 'bar' Cloning into 'bar'... Submodule path 'bar': checked out '00f1d87d3bd6948ef861f2b134daafabb10f7d6f'

All good.

The problem occurs in git-submodule when it replaces path components with '..'. It's assuming this will create a valid relative path by going up to the common root and then down, but this is an invalid assumption if any of the path components are symlinks.

Here's some partial output of git-submodule running with sh -x set, in a situation when the pwd is /bug:

++ git clone -n --separate-git-dir /Users/halley/bug/product/.git/modules/foo/modules/bar http://www.play-bow.org/repos/bar bar Cloning into 'bar'... +++ cd /Users/halley/bug/product/.git/modules/foo/modules/bar +++ pwd ++ a=/Users/halley/bug/product/.git/modules/foo/modules/bar/ +++ cd bar +++ pwd ++ b=/bug/product/foo/bar/ ++ case $a in ++ case $b in ++ test /Users/halley/bug/product/.git/modules/foo/modules/bar/ '!=' /Users/halley/bug/product/.git/modules/foo/modules/bar/ ++ test /bug/product/foo/bar/ '!=' /bug/product/foo/bar/ ++ test '' = '' ++ a=Users/halley/bug/product/.git/modules/foo/modules/bar/ ++ b=bug/product/foo/bar/ ++ test Users = bug ++ a=Users/halley/bug/product/.git/modules/foo/modules/bar ++ b=bug/product/foo/bar +++ echo bug/product/foo/bar +++ sed -e 's|[^/][^/]*|..|g' ++ rel=../../../.. ++ echo 'gitdir: ../../../../Users/halley/bug/product/.git/modules/foo/modules/bar' +++ echo Users/halley/bug/product/.git/modules/foo/modules/bar +++ sed -e 's|[^/][^/]*|..|g' ++ rel=../../../../../../../../.. ++ clear_local_git_env +++ git rev-parse --local-env-vars ++ unset GIT_ALTERNATE_OBJECT_DIRECTORIES GIT_CONFIG GIT_CONFIG_PARAMETERS GIT_OBJECT_DIRECTORY GIT_DIR GIT_WORK_TREE GIT_GRAFT_FILE GIT_INDEX_FILE GIT_NO_REPLACE_OBJECTS ++ cd bar ++ GIT_WORK_TREE=. ++ git config core.worktree ../../../../../../../../../bug/product/foo/bar fatal: Not a git repository: ../../../../Users/halley/bug/product/.git/modules/foo/modules/bar

This bit:

++ rel=../../../.. ++ echo 'gitdir: ../../../../Users/halley/bug/product/.git/modules/foo/modules/bar'

is wrong, because from /bug/product/foo/bar, ../../../.. is /Users/halley, not /.

If I replace the calls to "pwd" with "pwd -P", the problem goes away. Unfortunately I'm not sure how to fix the script portably, as neither pwd -P nor readlink(1) seem to be universally available.

Regards,
/Bob
Next: Phil Hord
Message 1 of 3 in “git-submodule path computation bug with recursive submodules”
  1. Bob HalleyJul 5, 2012
  2. Phil HordJul 5, 2012
  3. Jens LehmannJul 5, 2012

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.