Skip to content

Commit 4ae630e

Browse files
Fix status for old-style submodules with commondir
In some setups, old-style submodules (i.e. the ones with .git directory within theirs worktrees) with commondir can be of tremendous help. For example, commondir link can be used to avoid duplication of objects and also to keep branches in sync with multiple copies of the repo's worktree, while keeping the .git directory inside the worktree can be (ab?-)used to exploit the sharing of the same submodule worktree across different projects (this at least works on Windows with submodule directory being a directory junction, but having a junction is not relevant for reproducing the bug described below). Unfortunately, at the moment, when `git status` is run in the root repo of such a setup, it gives an output akin to this: ```sh fatal: unable to access '�??\1?/config': Invalid argument fatal: 'git status --porcelain=2' failed in submodule commonlibs ``` where `�??\1?` part of '�??\1?/config' varies from run to run, and `commonlibs` is the name of submodule's directory. Currently, when Git discovers old-style submodule , it spawns subprocess to get its status, like this one: ```sh cd commonlibs; unset GIT_PREFIX; GIT_DIR=.git git status --porcelain=2 ``` Unsurprisingly, the following output is also quite unexpected: ``` fatal: unable to access '`??L&?/config': Invalid argument ``` The core reason for these is that global repository field for commondir is not being cleared to `NULL` after being `free()`'d in `repo_set_commondir()`, which is precisely what this commit fixes. Regarding the further details of the case of investigation, this value of struct pointed by the global `the_repository` pointer is checked for being not-NULL down in the callstack in compatibility layer for MinGW in a function that is called by `repo_set_commondir()` before the `free()`'d value gets assigned in its body (i.e. the body of `repo_set_commondir()`). Backtrace from the check is: ``` #0 mingw_open (filename=0x<address-25> ".git/commondir", oflags=0) at compat/mingw.c:784 #1 0x<address-27> in strbuf_read_file (sb=0x<address-26>, path=0x<address-25> ".git/commondir", hint=0) at strbuf.c:758 #2 0x<address-24> in get_common_dir_noenv (sb=0x<address-23>, gitdir=0x<address-22> ".git") at setup.c:313 #3 0x<address-21> in repo_set_commondir (repo=0x<address-19> <the_repo>, commondir=0x0) at repository.c:57 #4 0x<address-20> in repo_set_gitdir (repo=0x<address-19> <the_repo>, root=0x<address-15> ".git", o=0x<address-18>) at repository.c:76 #5 0x<address-17> in setup_git_env (git_dir=0x<address-15> ".git") at environment.c:179 #6 0x<address-16> in set_git_dir_1 (path=0x<address-15> ".git") at environment.c:334 #7 0x<address-14> in update_relative_gitdir (name=0x0, old_cwd=0x<address-13> "C:/Users/%username%/<root-repo-name>/commonlibs", new_cwd=0x<address-11> "C:/Users/%username%/<root-repo-name>/commonlibs", data=0x0) at environment.c:348 #8 0x<address-12> in chdir_notify ( new_cwd=0x<address-11> "C:/Users/%username%/<root-repo-name>/commonlibs") at chdir-notify.c:72 #9 0x<address-10> in setup_work_tree () at setup.c:428 #10 0x<address-9> in run_builtin (p=0x<address-8> <commands+2856>, argc=2, argv=0x<address-2>) at git.c:458 #11 0x<address-7> in handle_builtin (argc=2, argv=0x<address-2>) at git.c:721 #12 0x<address-6> in run_argv (argcp=0x<address-5>, argv=0x<address-4>) at git.c:788 #13 0x<address-3> in cmd_main (argc=2, argv=0x<address-2>) at git.c:921 #14 0x<address-1> in main (argc=6, argv=0x<address-0>) at common-main.c:56 ``` Backtrace from the death is: ``` #0 die_errno (fmt=0x<address-42> <result_type+2002> "unable to access '%s'") at usage.c:210 #1 0x<address-41> in access_or_die ( path=0x<address-40> "`\001\r��\004/config", mode=4, flag=0) at wrapper.c:667 #2 0x<address-39> in do_git_config_sequence (opts=0x<address-35>, fn=0x<address-37> <git_config_include>, data=0x<address-36>) at config.c:2142 #3 0x<address-38> in config_with_options ( fn=0x<address-37> <git_config_include>, data=0x<address-36>, config_source=0x0, opts=0x<address-35>) at config.c:2198 #4 0x<address-34> in repo_read_config (repo=0x<address-19> <the_repo>) at config.c:2524 #5 0x<address-33> in git_config_check_init ( repo=0x<address-19> <the_repo>) at config.c:2543 #6 0x<address-32> in repo_config_get_bool ( repo=0x<address-19> <the_repo>, key=0x<address-30> <pad+3116> "windows.appendatomically", dest=0x<address-29> <append_atomically>) at config.c:2612 #7 0x<address-31> in git_config_get_bool ( key=0x<address-30> <pad+3116> "windows.appendatomically", dest=0x<address-29> <append_atomically>) at config.c:2714 #8 0x<address-28> in mingw_open ( filename=0x<address-25> ".git/commondir", oflags=0) at compat/mingw.c:785 #9 0x<address-27> in strbuf_read_file (sb=0x<address-26>, path=0x<address-25> ".git/commondir", hint=0) at strbuf.c:758 #10 0x<address-24> in get_common_dir_noenv (sb=0x<address-23>, gitdir=0x<address-22> ".git") at setup.c:313 #11 0x<address-21> in repo_set_commondir (repo=0x<address-19> <the_repo>, commondir=0x0) at repository.c:57 #12 0x<address-20> in repo_set_gitdir (repo=0x<address-19> <the_repo>, root=0x<address-15> ".git", o=0x<address-18>) at repository.c:76 #13 0x<address-17> in setup_git_env (git_dir=0x<address-15> ".git") at environment.c:179 #14 0x<address-16> in set_git_dir_1 (path=0x<address-15> ".git") at environment.c:334 #15 0x<address-14> in update_relative_gitdir (name=0x0, old_cwd=0x<address-13> "C:/Users/%username%/<root-repo-name>/commonlibs", new_cwd=0x<address-11> "C:/Users/%username%/<root-repo-name>/commonlibs", data=0x0) at environment.c:348 #16 0x<address-12> in chdir_notify ( new_cwd=0x<address-11> "C:/Users/%username%/<root-repo-name>/commonlibs") at chdir-notify.c:72 #17 0x<address-10> in setup_work_tree () at setup.c:428 #18 0x<address-9> in run_builtin (p=0x<address-8> <commands+2856>, argc=2, argv=0x<address-2>) at git.c:458 #19 0x<address-7> in handle_builtin (argc=2, argv=0x<address-2>) at git.c:721 #20 0x<address-6> in run_argv (argcp=0x<address-5>, argv=0x<address-4>) at git.c:788 #21 0x<address-3> in cmd_main (argc=2, argv=0x<address-2>) at git.c:921 #22 0x<address-1> in main (argc=6, argv=0x<address-0>) at common-main.c:56 ``` Signed-off-by: Andrey Zabavnikov <[email protected]>
1 parent be88dd9 commit 4ae630e

File tree

1 file changed

+1
-1
lines changed

1 file changed

+1
-1
lines changed

repository.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ static void repo_set_commondir(struct repository *repo,
4646
{
4747
struct strbuf sb = STRBUF_INIT;
4848

49-
free(repo->commondir);
49+
FREE_AND_NULL(repo->commondir);
5050

5151
if (commondir) {
5252
repo->different_commondir = 1;

0 commit comments

Comments
 (0)