The merge-recursive logic already had the ability to ignore the working
directory and operate entirely on the index -- it needed to do this when
creating a virtual merge base, i.e. when o->call_depth > 0.

The only trick here is that o->call_depth > 0 was also checked to
determine whether all merges conflicts should be forcibly immediately
resolved (typically by treating a copy of the code with conflict markers
still in it as the resolution) in order to get us some actual base tree
to work with.

Introduce a new merge option o->index_only which is true whenver either
--index-only is passed or o->call_depth > 0, and make the portions of
merge-recursive that are about operating only on the index look at
o->index_only, and the portions that are about forcibly immediately
resolving conflicts check o->call_depth.

Signed-off-by: Elijah Newren <new...@gmail.com>
---
 merge-recursive.c           | 37 ++++++++++++++++++++++---------------
 t/t6043-merge-index-only.sh | 12 ++++++------
 2 files changed, 28 insertions(+), 21 deletions(-)

diff --git a/merge-recursive.c b/merge-recursive.c
index b346ed6..6af37ed 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -406,10 +406,11 @@ static void record_df_conflict_files(struct merge_options 
*o,
        int i;
 
        /*
-        * If we're merging merge-bases, we don't want to bother with
-        * any working directory changes.
+        * If we're doing an index-only merge, we don't need to check for
+        * which files to remove from the working copy to make room for
+        * paths below directories of D/F conflicts; we can just exit early.
         */
-       if (o->call_depth)
+       if (o->index_only)
                return;
 
        /* Ensure D/F conflicts are adjacent in the entries list. */
@@ -581,7 +582,7 @@ static int remove_file(struct merge_options *o, int clean,
                       const char *path, int no_wd)
 {
        int update_cache = o->call_depth || clean;
-       int update_working_directory = !o->call_depth && !no_wd;
+       int update_working_directory = !o->index_only && !no_wd;
 
        if (update_cache) {
                if (remove_file_from_cache(path))
@@ -622,7 +623,7 @@ static char *unique_path(struct merge_options *o, const 
char *path, const char *
        base_len = newpath.len;
        while (string_list_has_string(&o->current_file_set, newpath.buf) ||
               string_list_has_string(&o->current_directory_set, newpath.buf) ||
-              (!o->call_depth && file_exists(newpath.buf))) {
+              (!o->index_only && file_exists(newpath.buf))) {
                strbuf_setlen(&newpath, base_len);
                strbuf_addf(&newpath, "_%d", suffix++);
        }
@@ -742,7 +743,7 @@ static void update_file_flags(struct merge_options *o,
                              int update_cache,
                              int update_wd)
 {
-       if (o->call_depth)
+       if (o->index_only)
                update_wd = 0;
 
        if (update_wd) {
@@ -813,7 +814,7 @@ static void update_file(struct merge_options *o,
                        unsigned mode,
                        const char *path)
 {
-       update_file_flags(o, sha, mode, path, o->call_depth || clean, 
!o->call_depth);
+       update_file_flags(o, sha, mode, path, o->call_depth || clean, 
!o->index_only);
 }
 
 /* Low level file merging, update and removal */
@@ -1017,7 +1018,7 @@ static void handle_change_delete(struct merge_options *o,
                                 const char *change, const char *change_past)
 {
        char *renamed = NULL;
-       if (dir_in_way(path, !o->call_depth)) {
+       if (dir_in_way(path, !o->index_only)) {
                renamed = unique_path(o, path, a_sha ? o->branch1 : o->branch2);
        }
 
@@ -1145,7 +1146,7 @@ static void handle_file(struct merge_options *o,
                remove_file(o, 0, rename->path, 0);
                dst_name = unique_path(o, rename->path, cur_branch);
        } else {
-               if (dir_in_way(rename->path, !o->call_depth)) {
+               if (dir_in_way(rename->path, !o->index_only)) {
                        dst_name = unique_path(o, rename->path, cur_branch);
                        output(o, 1, _("%s is a directory in %s adding as %s 
instead"),
                               rename->path, other_branch, dst_name);
@@ -1234,8 +1235,8 @@ static void conflict_rename_rename_2to1(struct 
merge_options *o,
               a->path, c1->path, ci->branch1,
               b->path, c2->path, ci->branch2);
 
-       remove_file(o, 1, a->path, o->call_depth || 
would_lose_untracked(a->path));
-       remove_file(o, 1, b->path, o->call_depth || 
would_lose_untracked(b->path));
+       remove_file(o, 1, a->path, o->index_only || 
would_lose_untracked(a->path));
+       remove_file(o, 1, b->path, o->index_only || 
would_lose_untracked(b->path));
 
        mfi_c1 = merge_file_special_markers(o, a, c1, &ci->ren1_other,
                                            o->branch1, c1->path,
@@ -1619,7 +1620,7 @@ static int merge_content(struct merge_options *o,
                         o->branch2 == rename_conflict_info->branch1) ?
                        pair1->two->path : pair1->one->path;
 
-               if (dir_in_way(path, !o->call_depth))
+               if (dir_in_way(path, !o->index_only))
                        df_conflict_remains = 1;
        }
        mfi = merge_file_special_markers(o, &one, &a, &b,
@@ -1639,7 +1640,7 @@ static int merge_content(struct merge_options *o,
                path_renamed_outside_HEAD = !path2 || !strcmp(path, path2);
                if (!path_renamed_outside_HEAD) {
                        add_cacheinfo(mfi.mode, mfi.sha, path,
-                                     0, (!o->call_depth), 0);
+                                     0, (!o->index_only), 0);
                        return mfi.clean;
                }
        } else
@@ -1767,7 +1768,7 @@ static int process_entry(struct merge_options *o,
                        sha = b_sha;
                        conf = _("directory/file");
                }
-               if (dir_in_way(path, !o->call_depth)) {
+               if (dir_in_way(path, !o->index_only)) {
                        char *new_path = unique_path(o, path, add_branch);
                        clean_merge = 0;
                        output(o, 1, _("CONFLICT (%s): There is a directory 
with name %s in %s. "
@@ -1819,7 +1820,7 @@ int merge_trees(struct merge_options *o,
                return 1;
        }
 
-       code = git_merge_trees(o->call_depth, common, head, merge);
+       code = git_merge_trees(o->index_only, common, head, merge);
 
        if (code != 0) {
                if (show(o, 4) || o->call_depth)
@@ -1899,6 +1900,7 @@ int merge_recursive(struct merge_options *o,
        struct commit *merged_common_ancestors;
        struct tree *mrtree = mrtree;
        int clean;
+       int prev_index_only_setting;
 
        if (show(o, 4)) {
                output(o, 4, _("Merging:"));
@@ -1929,9 +1931,12 @@ int merge_recursive(struct merge_options *o,
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
 
+       prev_index_only_setting = o->index_only;
+
        for (iter = ca; iter; iter = iter->next) {
                const char *saved_b1, *saved_b2;
                o->call_depth++;
+               o->index_only = 1;
                /*
                 * When the merge fails, the result contains files
                 * with conflict markers. The cleanness flag is
@@ -1954,6 +1959,8 @@ int merge_recursive(struct merge_options *o,
                        die(_("merge returned no commit"));
        }
 
+       o->index_only = prev_index_only_setting;
+
        discard_cache();
        if (!o->call_depth)
                read_cache();
diff --git a/t/t6043-merge-index-only.sh b/t/t6043-merge-index-only.sh
index 9bb64d8..2e1d953 100755
--- a/t/t6043-merge-index-only.sh
+++ b/t/t6043-merge-index-only.sh
@@ -28,7 +28,7 @@ test_expect_success 'setup rename/modify merge' '
        git commit -m C
 '
 
-test_expect_failure '--index-only with rename/modify works in non-bare-clone' '
+test_expect_success '--index-only with rename/modify works in non-bare-clone' '
        git checkout B^0 &&
 
        git merge --index-only -s recursive C^0 &&
@@ -43,7 +43,7 @@ test_expect_failure '--index-only with rename/modify works in 
non-bare-clone' '
        test $(git rev-parse B:a) = $(git rev-parse :b)
 '
 
-test_expect_failure '--index-only with rename/modify works in a bare clone' '
+test_expect_success '--index-only with rename/modify works in a bare clone' '
        git clone --bare . bare.clone &&
        (cd bare.clone &&
 
@@ -136,7 +136,7 @@ test_expect_success 'setup single-file criss-cross 
resolvable with recursive str
        rm -f answer
 '
 
-test_expect_failure 'recursive --index-only in non-bare repo' '
+test_expect_success 'recursive --index-only in non-bare repo' '
        git reset --hard &&
        git checkout L2^0 &&
 
@@ -150,7 +150,7 @@ test_expect_failure 'recursive --index-only in non-bare 
repo' '
        test $(git rev-parse L2:contents) = $(git hash-object contents)
 '
 
-test_expect_failure 'recursive --index-only in bare repo' '
+test_expect_success 'recursive --index-only in bare repo' '
        git clone --bare . bare.clone &&
        (cd bare.clone &&
 
@@ -406,7 +406,7 @@ test_expect_success '--index-only ours, bare' '
        )
 '
 
-test_expect_failure '--index-only subtree, non-bare' '
+test_expect_success '--index-only subtree, non-bare' '
        git reset --hard &&
        git checkout B^0 &&
 
@@ -420,7 +420,7 @@ test_expect_failure '--index-only subtree, non-bare' '
        test ! -f e
 '
 
-test_expect_failure '--index-only subtree, bare' '
+test_expect_success '--index-only subtree, bare' '
        rm -rf bare.clone &&
        git clone --bare . bare.clone &&
        (cd bare.clone &&
-- 
2.8.0.18.gc685494

--
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