unpack-trees.c: assume submodules are clean during check-out
authorSven Verdoolaege <skimo@kotnet.org>
Tue, 17 Jul 2007 18:28:28 +0000 (20:28 +0200)
committerJunio C Hamano <gitster@pobox.com>
Thu, 19 Jul 2007 00:01:00 +0000 (17:01 -0700)
In particular, when moving back to a commit without a given submodule
and then moving back forward to a commit with the given submodule,
we shouldn't complain that updating would lose untracked file in
the submodule, because git currently does not checkout subprojects
during superproject check-out.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/t7400-submodule-basic.sh
unpack-trees.c

index 5e91db64e95d25049e298f37a2dadb436af8c8d0..e8ce7cdb833e3c0f45ffb52d85d7572839e3e34a 100755 (executable)
@@ -21,6 +21,10 @@ subcommands of git-submodule.
 #  -add an entry to .gitmodules for submodule 'example'
 #
 test_expect_success 'Prepare submodule testing' '
+       : > t &&
+       git-add t &&
+       git-commit -m "initial commit" &&
+       git branch initial HEAD &&
        mkdir lib &&
        cd lib &&
        git init &&
@@ -166,4 +170,9 @@ test_expect_success 'status should be "up-to-date" after update' '
        git-submodule status | grep "^ $rev1"
 '
 
+test_expect_success 'checkout superproject with subproject already present' '
+       git-checkout initial &&
+       git-checkout master
+'
+
 test_done
index 89dd279f89c7648ec333c59634b3169251eec7ab..7cc029e564f3a13b3352bb5f5feae12254421f68 100644 (file)
@@ -5,6 +5,7 @@
 #include "cache-tree.h"
 #include "unpack-trees.h"
 #include "progress.h"
+#include "refs.h"
 
 #define DBRT_DEBUG 1
 
@@ -425,11 +426,24 @@ static void invalidate_ce_path(struct cache_entry *ce)
                cache_tree_invalidate_path(active_cache_tree, ce->name);
 }
 
-static int verify_clean_subdirectory(const char *path, const char *action,
+/*
+ * Check that checking out ce->sha1 in subdir ce->name is not
+ * going to overwrite any working files.
+ *
+ * Currently, git does not checkout subprojects during a superproject
+ * checkout, so it is not going to overwrite anything.
+ */
+static int verify_clean_submodule(struct cache_entry *ce, const char *action,
+                                     struct unpack_trees_options *o)
+{
+       return 0;
+}
+
+static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
                                      struct unpack_trees_options *o)
 {
        /*
-        * we are about to extract "path"; we would not want to lose
+        * we are about to extract "ce->name"; we would not want to lose
         * anything in the existing directory there.
         */
        int namelen;
@@ -437,13 +451,24 @@ static int verify_clean_subdirectory(const char *path, const char *action,
        struct dir_struct d;
        char *pathbuf;
        int cnt = 0;
+       unsigned char sha1[20];
+
+       if (S_ISGITLINK(ntohl(ce->ce_mode)) &&
+           resolve_gitlink_ref(ce->name, "HEAD", sha1) == 0) {
+               /* If we are not going to update the submodule, then
+                * we don't care.
+                */
+               if (!hashcmp(sha1, ce->sha1))
+                       return 0;
+               return verify_clean_submodule(ce, action, o);
+       }
 
        /*
         * First let's make sure we do not have a local modification
         * in that directory.
         */
-       namelen = strlen(path);
-       pos = cache_name_pos(path, namelen);
+       namelen = strlen(ce->name);
+       pos = cache_name_pos(ce->name, namelen);
        if (0 <= pos)
                return cnt; /* we have it as nondirectory */
        pos = -pos - 1;
@@ -451,7 +476,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
                struct cache_entry *ce = active_cache[i];
                int len = ce_namelen(ce);
                if (len < namelen ||
-                   strncmp(path, ce->name, namelen) ||
+                   strncmp(ce->name, ce->name, namelen) ||
                    ce->name[namelen] != '/')
                        break;
                /*
@@ -469,16 +494,16 @@ static int verify_clean_subdirectory(const char *path, const char *action,
         * present file that is not ignored.
         */
        pathbuf = xmalloc(namelen + 2);
-       memcpy(pathbuf, path, namelen);
+       memcpy(pathbuf, ce->name, namelen);
        strcpy(pathbuf+namelen, "/");
 
        memset(&d, 0, sizeof(d));
        if (o->dir)
                d.exclude_per_dir = o->dir->exclude_per_dir;
-       i = read_directory(&d, path, pathbuf, namelen+1, NULL);
+       i = read_directory(&d, ce->name, pathbuf, namelen+1, NULL);
        if (i)
                die("Updating '%s' would lose untracked files in it",
-                   path);
+                   ce->name);
        free(pathbuf);
        return cnt;
 }
@@ -487,7 +512,7 @@ static int verify_clean_subdirectory(const char *path, const char *action,
  * We do not want to remove or overwrite a working tree file that
  * is not tracked, unless it is ignored.
  */
-static void verify_absent(const char *path, const char *action,
+static void verify_absent(struct cache_entry *ce, const char *action,
                struct unpack_trees_options *o)
 {
        struct stat st;
@@ -495,15 +520,15 @@ static void verify_absent(const char *path, const char *action,
        if (o->index_only || o->reset || !o->update)
                return;
 
-       if (has_symlink_leading_path(path, NULL))
+       if (has_symlink_leading_path(ce->name, NULL))
                return;
 
-       if (!lstat(path, &st)) {
+       if (!lstat(ce->name, &st)) {
                int cnt;
 
-               if (o->dir && excluded(o->dir, path))
+               if (o->dir && excluded(o->dir, ce->name))
                        /*
-                        * path is explicitly excluded, so it is Ok to
+                        * ce->name is explicitly excluded, so it is Ok to
                         * overwrite it.
                         */
                        return;
@@ -515,7 +540,7 @@ static void verify_absent(const char *path, const char *action,
                         * files that are in "foo/" we would lose
                         * it.
                         */
-                       cnt = verify_clean_subdirectory(path, action, o);
+                       cnt = verify_clean_subdirectory(ce, action, o);
 
                        /*
                         * If this removed entries from the index,
@@ -543,7 +568,7 @@ static void verify_absent(const char *path, const char *action,
                 * delete this path, which is in a subdirectory that
                 * is being replaced with a blob.
                 */
-               cnt = cache_name_pos(path, strlen(path));
+               cnt = cache_name_pos(ce->name, strlen(ce->name));
                if (0 <= cnt) {
                        struct cache_entry *ce = active_cache[cnt];
                        if (!ce_stage(ce) && !ce->ce_mode)
@@ -551,7 +576,7 @@ static void verify_absent(const char *path, const char *action,
                }
 
                die("Untracked working tree file '%s' "
-                   "would be %s by merge.", path, action);
+                   "would be %s by merge.", ce->name, action);
        }
 }
 
@@ -575,7 +600,7 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
                }
        }
        else {
-               verify_absent(merge->name, "overwritten", o);
+               verify_absent(merge, "overwritten", o);
                invalidate_ce_path(merge);
        }
 
@@ -590,7 +615,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
        if (old)
                verify_uptodate(old, o);
        else
-               verify_absent(ce->name, "removed", o);
+               verify_absent(ce, "removed", o);
        ce->ce_mode = 0;
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
        invalidate_ce_path(ce);
@@ -707,18 +732,18 @@ int threeway_merge(struct cache_entry **stages,
        if (o->aggressive) {
                int head_deleted = !head && !df_conflict_head;
                int remote_deleted = !remote && !df_conflict_remote;
-               const char *path = NULL;
+               struct cache_entry *ce = NULL;
 
                if (index)
-                       path = index->name;
+                       ce = index;
                else if (head)
-                       path = head->name;
+                       ce = head;
                else if (remote)
-                       path = remote->name;
+                       ce = remote;
                else {
                        for (i = 1; i < o->head_idx; i++) {
                                if (stages[i] && stages[i] != o->df_conflict_entry) {
-                                       path = stages[i]->name;
+                                       ce = stages[i];
                                        break;
                                }
                        }
@@ -733,8 +758,8 @@ int threeway_merge(struct cache_entry **stages,
                    (remote_deleted && head && head_match)) {
                        if (index)
                                return deleted_entry(index, index, o);
-                       else if (path && !head_deleted)
-                               verify_absent(path, "removed", o);
+                       else if (ce && !head_deleted)
+                               verify_absent(ce, "removed", o);
                        return 0;
                }
                /*