This is rebased so the diff below (against the version on Junio's
repo) is only approximate. Changes include test fixes for Windows
port, $GIT_COMMON_DIR and $GIT_DIR/modules problems with submodules.
Patch 03/34 is rewritten to touch less in refs.c to reduce conflicts.
A lot of changes there are just revert.

diff --git a/Documentation/gitrepository-layout.txt 
b/Documentation/gitrepository-layout.txt
index 2b30a92..7173b38 100644
--- a/Documentation/gitrepository-layout.txt
+++ b/Documentation/gitrepository-layout.txt
@@ -248,9 +248,7 @@ commondir::
        incomplete without the repository pointed by "commondir".
 
 modules::
-       Contains the git-repositories of the submodules. This
-       directory is ignored if $GIT_COMMON_DIR is set and
-       "$GIT_COMMON_DIR/modules" will be used instead.
+       Contains the git-repositories of the submodules.
 
 worktrees::
        Contains worktree specific information of linked
diff --git a/builtin/checkout.c b/builtin/checkout.c
index 01d0f2f..e70e66c 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -865,7 +865,7 @@ static int prepare_linked_checkout(const struct 
checkout_opts *opts,
 
        if (!new->commit)
                die(_("no branch specified"));
-       if (file_exists(path))
+       if (file_exists(path) && !is_empty_dir(path))
                die(_("'%s' already exists"), path);
 
        len = strlen(path);
@@ -1207,7 +1207,7 @@ static int parse_branchname_arg(int argc, const char 
**argv,
        if (new->path && !force_detach && !*new_branch) {
                unsigned char sha1[20];
                int flag;
-               char *head_ref = resolve_refdup("HEAD", sha1, 0, &flag);
+               char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
                if (head_ref &&
                    (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)))
                        check_linked_checkouts(new);
diff --git a/environment.c b/environment.c
index d5b0788..8351007 100644
--- a/environment.c
+++ b/environment.c
@@ -101,6 +101,7 @@ const char * const local_repo_env[] = {
        NO_REPLACE_OBJECTS_ENVIRONMENT,
        GIT_PREFIX_ENVIRONMENT,
        GIT_SHALLOW_FILE_ENVIRONMENT,
+       GIT_COMMON_DIR_ENVIRONMENT,
        NULL
 };
 
diff --git a/path.c b/path.c
index 35d498e..a5c51a3 100644
--- a/path.c
+++ b/path.c
@@ -92,7 +92,7 @@ static void replace_dir(struct strbuf *buf, int len, const 
char *newdir)
 }
 
 static const char *common_list[] = {
-       "/branches", "/hooks", "/info", "!/logs", "/lost-found", "/modules",
+       "/branches", "/hooks", "/info", "!/logs", "/lost-found",
        "/objects", "/refs", "/remotes", "/worktrees", "/rr-cache", "/svn",
        "config", "!gc.pid", "packed-refs", "shallow",
        NULL
diff --git a/refs.c b/refs.c
index 3cefbd3..f7e48b0 100644
--- a/refs.c
+++ b/refs.c
@@ -1398,14 +1398,16 @@ static const char *handle_missing_loose_ref(const char 
*refname,
 }
 
 /* This function needs to return a meaningful errno on failure */
-const char *resolve_ref_unsafe(const char *refname, unsigned char *sha1, int 
reading, int *flag)
+static const char *resolve_ref_unsafe_1(const char *refname,
+                                       unsigned char *sha1,
+                                       int reading,
+                                       int *flags,
+                                       struct strbuf *sb_path)
 {
-       struct strbuf sb_path = STRBUF_INIT;
        int depth = MAXDEPTH;
        ssize_t len;
        char buffer[256];
        static char refname_buffer[256];
-       const char *ret;
 
        if (flag)
                *flag = 0;
@@ -1423,12 +1425,12 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
 
                if (--depth < 0) {
                        errno = ELOOP;
-                       goto fail;
+                       return NULL;
                }
 
-               strbuf_reset(&sb_path);
-               strbuf_git_path(&sb_path, "%s", refname);
-               path = sb_path.buf;
+               strbuf_reset(sb_path);
+               strbuf_git_path(sb_path, "%s", refname);
+               path = sb_path->buf;
 
                /*
                 * We might have to loop back here to avoid a race
@@ -1442,11 +1444,10 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
        stat_ref:
                if (lstat(path, &st) < 0) {
                        if (errno == ENOENT)
-                               ret = handle_missing_loose_ref(refname, sha1,
-                                                              reading, flag);
+                               return handle_missing_loose_ref(refname, sha1,
+                                                               reading, flag);
                        else
-                               ret = NULL;
-                       goto done;
+                               return NULL;
                }
 
                /* Follow "normalized" - ie "refs/.." symlinks by hand */
@@ -1457,7 +1458,7 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
                                        /* inconsistent with lstat; retry */
                                        goto stat_ref;
                                else
-                                       goto fail;
+                                       return NULL;
                        }
                        buffer[len] = 0;
                        if (starts_with(buffer, "refs/") &&
@@ -1473,7 +1474,7 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
                /* Is it a directory? */
                if (S_ISDIR(st.st_mode)) {
                        errno = EISDIR;
-                       goto fail;
+                       return NULL;
                }
 
                /*
@@ -1486,15 +1487,14 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
                                /* inconsistent with lstat; retry */
                                goto stat_ref;
                        else
-                               goto fail;
+                               return NULL;
                }
-
                len = read_in_full(fd, buffer, sizeof(buffer)-1);
                if (len < 0) {
                        int save_errno = errno;
                        close(fd);
                        errno = save_errno;
-                       goto fail;
+                       return NULL;
                }
                close(fd);
                while (len && isspace(buffer[len-1]))
@@ -1514,10 +1514,9 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
                                if (flag)
                                        *flag |= REF_ISBROKEN;
                                errno = EINVAL;
-                               goto fail;
+                               return NULL;
                        }
-                       ret = refname;
-                       goto done;
+                       return refname;
                }
                if (flag)
                        *flag |= REF_ISSYMREF;
@@ -1528,13 +1527,17 @@ const char *resolve_ref_unsafe(const char *refname, 
unsigned char *sha1, int rea
                        if (flag)
                                *flag |= REF_ISBROKEN;
                        errno = EINVAL;
-                       goto fail;
+                       return NULL;
                }
                refname = strcpy(refname_buffer, buf);
        }
-fail:
-       ret = NULL;
-done:
+}
+
+const char *resolve_ref_unsafe(const char *refname, int reading,
+                              unsigned char *sha1, int *flags)
+{
+       struct strbuf sb_path = STRBUF_INIT;
+       const char *ret = resolve_ref_unsafe_1(refname, reading,, sha1, flags, 
&sb_path);
        strbuf_release(&sb_path);
        return ret;
 }
@@ -2844,62 +2847,66 @@ static int copy_msg(char *buf, const char *msg)
 }
 
 /* This function must set a meaningful errno on failure */
-int log_ref_setup(const char *refname, struct strbuf *logfile)
+int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
 {
        int logfd, oflags = O_APPEND | O_WRONLY;
+       char *logfile;
 
-       strbuf_git_path(logfile, "logs/%s", refname);
+       strbuf_git_path(sb_logfile, "logs/%s", refname);
+       logfile = sb_logfile->buf;
+       /* make sure the rest of the function can't change "logfile" */
+       sb_logfile = NULL;
        if (log_all_ref_updates &&
            (starts_with(refname, "refs/heads/") ||
             starts_with(refname, "refs/remotes/") ||
             starts_with(refname, "refs/notes/") ||
             !strcmp(refname, "HEAD"))) {
-               if (safe_create_leading_directories(logfile->buf) < 0) {
+               if (safe_create_leading_directories(logfile) < 0) {
                        int save_errno = errno;
-                       error("unable to create directory for %s", 
logfile->buf);
+                       error("unable to create directory for %s", logfile);
                        errno = save_errno;
                        return -1;
                }
                oflags |= O_CREAT;
        }
 
-       logfd = open(logfile->buf, oflags, 0666);
+       logfd = open(logfile, oflags, 0666);
        if (logfd < 0) {
                if (!(oflags & O_CREAT) && errno == ENOENT)
                        return 0;
 
                if ((oflags & O_CREAT) && errno == EISDIR) {
-                       if (remove_empty_directories(logfile->buf)) {
+                       if (remove_empty_directories(logfile)) {
                                int save_errno = errno;
                                error("There are still logs under '%s'",
-                                     logfile->buf);
+                                     logfile);
                                errno = save_errno;
                                return -1;
                        }
-                       logfd = open(logfile->buf, oflags, 0666);
+                       logfd = open(logfile, oflags, 0666);
                }
 
                if (logfd < 0) {
                        int save_errno = errno;
-                       error("Unable to append to %s: %s", logfile->buf,
+                       error("Unable to append to %s: %s", logfile,
                              strerror(errno));
                        errno = save_errno;
                        return -1;
                }
        }
 
-       adjust_shared_perm(logfile->buf);
+       adjust_shared_perm(logfile);
        close(logfd);
        return 0;
 }
 
-static int log_ref_write(const char *refname, const unsigned char *old_sha1,
-                        const unsigned char *new_sha1, const char *msg)
+static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
+                          const unsigned char *new_sha1, const char *msg,
+                          struct strbuf *sb_log_file)
 {
        int logfd, result, written, oflags = O_APPEND | O_WRONLY;
        unsigned maxlen, len;
        int msglen;
-       struct strbuf sb_log_file = STRBUF_INIT;
        const char *log_file;
        char *logrec;
        const char *committer;
@@ -2907,14 +2914,16 @@ static int log_ref_write(const char *refname, const 
unsigned char *old_sha1,
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
 
-       result = log_ref_setup(refname, &sb_log_file);
+       result = log_ref_setup(refname, sb_log_file);
        if (result)
-               goto done;
-       log_file = sb_log_file.buf;
+               return result;
+       log_file = sb_log_file->buf;
+       /* make sure the rest of the function can't change "log_file" */
+       sb_log_file = NULL;
 
        logfd = open(log_file, oflags);
        if (logfd < 0)
-               goto done;
+               return 0;
        msglen = msg ? strlen(msg) : 0;
        committer = git_committer_info(0);
        maxlen = strlen(committer) + msglen + 100;
@@ -2932,19 +2941,24 @@ static int log_ref_write(const char *refname, const 
unsigned char *old_sha1,
                close(logfd);
                error("Unable to append to %s", log_file);
                errno = save_errno;
-               result = -1;
-               goto done;
+               return -1;
        }
        if (close(logfd)) {
                int save_errno = errno;
                error("Unable to append to %s", log_file);
                errno = save_errno;
-               result = -1;
-               goto done;
+               return -1;
        }
-done:
-       strbuf_release(&sb_log_file);
-       return result;
+       return 0;
+}
+
+static int log_ref_write(const char *refname, const unsigned char *old_sha1,
+                        const unsigned char *new_sha1, const char *msg)
+{
+       struct strbuf sb = STRBUF_INIT;
+       int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
+       strbuf_release(&sb);
+       return ret;
 }
 
 int is_branch(const char *refname)
diff --git a/t/t1501-worktree.sh b/t/t1501-worktree.sh
index e6ac7a4..4df7a2f 100755
--- a/t/t1501-worktree.sh
+++ b/t/t1501-worktree.sh
@@ -366,7 +366,7 @@ test_expect_success 'GIT_DIR set (1)' '
 
 test_expect_success 'GIT_DIR set (2)' '
        echo "gitdir: repo.git/repos/foo" >gitfile &&
-       echo "$TRASH_DIRECTORY/repo.git" >repo.git/repos/foo/commondir &&
+       echo "$(pwd)/repo.git" >repo.git/repos/foo/commondir &&
        (
                cd work &&
                GIT_DIR=../gitfile git rev-parse --git-common-dir >actual &&
diff --git a/t/t2025-checkout-to.sh b/t/t2025-checkout-to.sh
index eddd325..915b506 100755
--- a/t/t2025-checkout-to.sh
+++ b/t/t2025-checkout-to.sh
@@ -13,10 +13,15 @@ test_expect_success 'checkout --to not updating paths' '
 '
 
 test_expect_success 'checkout --to an existing worktree' '
-       mkdir existing &&
+       mkdir -p existing/subtree &&
        test_must_fail git checkout --detach --to existing master
 '
 
+test_expect_success 'checkout --to an existing empty worktree' '
+       mkdir existing_empty &&
+       git checkout --detach --to existing_empty master
+'
+
 test_expect_success 'checkout --to refuses to checkout locked branch' '
        test_must_fail git checkout --to zere master &&
        ! test -d zere &&
diff --git a/t/t2026-prune-linked-checkouts.sh 
b/t/t2026-prune-linked-checkouts.sh
index 3622800..170aefe 100755
--- a/t/t2026-prune-linked-checkouts.sh
+++ b/t/t2026-prune-linked-checkouts.sh
@@ -57,7 +57,7 @@ test_expect_success 'prune directories with invalid gitdir' '
 test_expect_success 'prune directories with gitdir pointing to nowhere' '
        mkdir -p .git/worktrees/def/abc &&
        : >.git/worktrees/def/def &&
-       echo "$TRASH_DIRECTORY"/nowhere >.git/worktrees/def/gitdir &&
+       echo "$(pwd)"/nowhere >.git/worktrees/def/gitdir &&
        git prune --worktrees --verbose >actual &&
        test_i18ngrep "Removing worktrees/def: gitdir file points to 
non-existent location" actual &&
        ! test -d .git/worktrees/def &&
@@ -76,7 +76,7 @@ test_expect_success 'not prune recent checkouts' '
        test_when_finished rm -r .git/worktrees
        mkdir zz &&
        mkdir -p .git/worktrees/jlm &&
-       echo "$TRASH_DIRECTORY"/zz >.git/worktrees/jlm/gitdir &&
+       echo "$(pwd)"/zz >.git/worktrees/jlm/gitdir &&
        git prune --worktrees --verbose --expire=2.days.ago &&
        test -d .git/worktrees/jlm
 '
diff --git a/t/t7410-submodule-checkout-to.sh b/t/t7410-submodule-checkout-to.sh
new file mode 100755
index 0000000..8f30aed
--- /dev/null
+++ b/t/t7410-submodule-checkout-to.sh
@@ -0,0 +1,50 @@
+#!/bin/sh
+
+test_description='Combination of submodules and multiple workdirs'
+
+. ./test-lib.sh
+
+base_path=$(pwd -P)
+
+test_expect_success 'setup: make origin' \
+    'mkdir -p origin/sub && ( cd origin/sub && git init &&
+       echo file1 >file1 &&
+       git add file1 &&
+       git commit -m file1 ) &&
+    mkdir -p origin/main && ( cd origin/main && git init &&
+       git submodule add ../sub &&
+       git commit -m "add sub" ) &&
+    ( cd origin/sub &&
+       echo file1updated >file1 &&
+       git add file1 &&
+       git commit -m "file1 updated" ) &&
+    ( cd origin/main/sub && git pull ) &&
+    ( cd origin/main &&
+       git add sub &&
+       git commit -m "sub updated" )'
+
+test_expect_success 'setup: clone' \
+    'mkdir clone && ( cd clone &&
+       git clone --recursive "$base_path/origin/main")'
+
+rev1_hash_main=$(git --git-dir=origin/main/.git show --pretty=format:%h -q 
"HEAD~1")
+rev1_hash_sub=$(git --git-dir=origin/sub/.git show --pretty=format:%h -q 
"HEAD~1")
+
+test_expect_success 'checkout main' \
+    'mkdir default_checkout &&
+    (cd clone/main &&
+       git checkout --to "$base_path/default_checkout/main" "$rev1_hash_main")'
+
+test_expect_failure 'can see submodule diffs just after checkout' \
+    '(cd default_checkout/main && git diff --submodule master"^!" | grep 
"file1 updated")'
+
+test_expect_success 'checkout main and initialize independed clones' \
+    'mkdir fully_cloned_submodule &&
+    (cd clone/main &&
+       git checkout --to "$base_path/fully_cloned_submodule/main" 
"$rev1_hash_main") &&
+    (cd fully_cloned_submodule/main && git submodule update)'
+
+test_expect_success 'can see submodule diffs after independed cloning' \
+    '(cd fully_cloned_submodule/main && git diff --submodule master"^!" | grep 
"file1 updated")'
+
+test_done
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to