Signed-off-by: Stefan Beller <sbel...@google.com>
---
 entry.c        |  7 +++---
 unpack-trees.c | 76 +++++++++++++++++++++++++++++++++++++++++++++-------------
 unpack-trees.h |  1 +
 3 files changed, 65 insertions(+), 19 deletions(-)

diff --git a/entry.c b/entry.c
index a668025b8e..3ed885b886 100644
--- a/entry.c
+++ b/entry.c
@@ -267,7 +267,7 @@ int checkout_entry(struct cache_entry *ce,
 
        if (!check_path(path.buf, path.len, &st, state->base_dir_len)) {
                unsigned changed = ce_match_stat(ce, &st, 
CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
-               if (!changed)
+               if (!changed && (!S_ISDIR(st.st_mode) || 
!S_ISGITLINK(ce->ce_mode)))
                        return 0;
                if (!state->force) {
                        if (!state->quiet)
@@ -284,9 +284,10 @@ int checkout_entry(struct cache_entry *ce,
                 * just do the right thing)
                 */
                if (S_ISDIR(st.st_mode)) {
-                       /* If it is a gitlink, leave it alone! */
-                       if (S_ISGITLINK(ce->ce_mode))
+                       if (S_ISGITLINK(ce->ce_mode)) {
+                               schedule_submodule_for_update(ce, 1);
                                return 0;
+                       }
                        if (!state->force)
                                return error("%s is a directory", path.buf);
                        remove_subtree(&path);
diff --git a/unpack-trees.c b/unpack-trees.c
index db03293347..8b0f6dfd1a 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -29,6 +29,9 @@ static const char 
*unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
        /* ERROR_NOT_UPTODATE_DIR */
        "Updating '%s' would lose untracked files in it",
 
+       /* ERROR_NOT_UPTODATE_SUBMODULE */
+       "Updating submodule '%s' would lose modifications in it",
+
        /* ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN */
        "Untracked working tree file '%s' would be overwritten by merge.",
 
@@ -81,6 +84,9 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options 
*opts,
        msgs[ERROR_NOT_UPTODATE_DIR] =
                _("Updating the following directories would lose untracked 
files in it:\n%s");
 
+       msgs[ERROR_NOT_UPTODATE_SUBMODULE] =
+               _("Updating the following submodules would lose modifications 
in them:\n%s");
+
        if (!strcmp(cmd, "checkout"))
                msg = advice_commit_before_merge
                      ? _("The following untracked working tree files would be 
removed by checkout:\n%%s"
@@ -1320,19 +1326,17 @@ static int verify_uptodate_1(const struct cache_entry 
*ce,
                return 0;
 
        if (!lstat(ce->name, &st)) {
-               int flags = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE;
-               unsigned changed = ie_match_stat(o->src_index, ce, &st, flags);
-               if (!changed)
-                       return 0;
-               /*
-                * NEEDSWORK: the current default policy is to allow
-                * submodule to be out of sync wrt the superproject
-                * index.  This needs to be tightened later for
-                * submodules that are marked to be automatically
-                * checked out.
-                */
-               if (S_ISGITLINK(ce->ce_mode))
-                       return 0;
+               if (S_ISGITLINK(ce->ce_mode)) {
+                       if (!submodule_is_interesting(ce->name))
+                               return 0;
+                       if (ce_stage(ce) ? is_submodule_checkout_safe(ce->name, 
&ce->oid)
+                           : !is_submodule_modified(ce->name, 1))
+                               return 0;
+               } else {
+                       int flags = CE_MATCH_IGNORE_VALID | 
CE_MATCH_IGNORE_SKIP_WORKTREE;
+                       if (!ie_match_stat(o->src_index, ce, &st, flags))
+                               return 0;
+               }
                errno = 0;
        }
        if (errno == ENOENT)
@@ -1355,6 +1359,38 @@ static int verify_uptodate_sparse(const struct 
cache_entry *ce,
        return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
 }
 
+/*
+ * When a submodule gets turned into an unmerged entry, we want it to be
+ * up-to-date regarding the merge changes.
+ */
+static int verify_uptodate_submodule(const struct cache_entry *old,
+                                    const struct cache_entry *new,
+                                    struct unpack_trees_options *o)
+{
+       struct stat st;
+
+       if (o->index_only ||
+           (!((old->ce_flags & CE_VALID) || ce_skip_worktree(old)) &&
+             (o->reset || ce_uptodate(old))))
+               return 0;
+
+       if (!submodule_is_interesting(new->name))
+               return 0;
+
+       if (lstat(old->name, &st)) {
+               if (errno == ENOENT)
+                       return 0;
+               return o->gently ? -1 :
+                       add_rejected_path(o, ERROR_NOT_UPTODATE_SUBMODULE,
+                                         old->name);
+       }
+
+       if (S_ISGITLINK(new->ce_mode))
+               return !is_submodule_checkout_safe(new->name, &new->oid);
+       else
+               return !ok_to_remove_submodule(old->name);
+}
+
 static void invalidate_ce_path(const struct cache_entry *ce,
                               struct unpack_trees_options *o)
 {
@@ -1616,9 +1652,17 @@ static int merged_entry(const struct cache_entry *ce,
                        copy_cache_entry(merge, old);
                        update = 0;
                } else {
-                       if (verify_uptodate(old, o)) {
-                               free(merge);
-                               return -1;
+                       if (S_ISGITLINK(old->ce_mode) ||
+                           S_ISGITLINK(merge->ce_mode)) {
+                               if (verify_uptodate_submodule(old, merge, o)) {
+                                       free(merge);
+                                       return -1;
+                               }
+                       } else {
+                               if (verify_uptodate(old, o)) {
+                                       free(merge);
+                                       return -1;
+                               }
                        }
                        /* Migrate old flags over */
                        update |= old->ce_flags & (CE_SKIP_WORKTREE | 
CE_NEW_SKIP_WORKTREE);
diff --git a/unpack-trees.h b/unpack-trees.h
index 36a73a6d00..bee874088a 100644
--- a/unpack-trees.h
+++ b/unpack-trees.h
@@ -15,6 +15,7 @@ enum unpack_trees_error_types {
        ERROR_WOULD_OVERWRITE = 0,
        ERROR_NOT_UPTODATE_FILE,
        ERROR_NOT_UPTODATE_DIR,
+       ERROR_NOT_UPTODATE_SUBMODULE,
        ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN,
        ERROR_WOULD_LOSE_UNTRACKED_REMOVED,
        ERROR_BIND_OVERLAP,
-- 
2.11.0.rc2.28.g2673dad

Reply via email to