Code

merge-recursive --renormalize
authorJonathan Nieder <jrnieder@gmail.com>
Thu, 5 Aug 2010 11:32:41 +0000 (06:32 -0500)
committerJunio C Hamano <gitster@pobox.com>
Fri, 6 Aug 2010 16:20:02 +0000 (09:20 -0700)
Teach "git merge-recursive" a --renormalize option to enable the
merge.renormalize configuration.  The --no-renormalize option can
be used to override it in the negative.

So in the future, you might be able to, e.g.:

git checkout -m -Xrenormalize otherbranch

or

git revert -Xrenormalize otherpatch

or

git pull --rebase -Xrenormalize

The bad part: merge.renormalize is still not honored for most
commands.  And it reveals lots of places that -X has not been plumbed
in (so we get "git merge -Xrenormalize" but not much else).

NEEDSWORK: tests

Cc: Eyvind Bernhardsen <eyvind.bernhardsen@gmail.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/merge-strategies.txt
builtin/checkout.c
builtin/merge-recursive.c
builtin/merge.c
builtin/revert.c
cache.h
environment.c
merge-recursive.c

index a5bc1dbb95b466d0c6e37f683c886663908375e7..049313d6015758fb3e95c21fecc40e021e8aa4bd 100644 (file)
@@ -40,6 +40,18 @@ the other tree did, declaring 'our' history contains all that happened in it.
 theirs;;
        This is opposite of 'ours'.
 
+renormalize;;
+       This runs a virtual check-out and check-in of all three stages
+       of a file when resolving a three-way merge.  This option is
+       meant to be used when merging branches with different clean
+       filters or end-of-line normalization rules.  See "Merging
+       branches with differing checkin/checkout attributes" in
+       linkgit:gitattributes[5] for details.
+
+no-renormalize;;
+       Disables the `renormalize` option.  This overrides the
+       `merge.renormalize` configuration variable.
+
 subtree[=path];;
        This option is a more advanced form of 'subtree' strategy, where
        the strategy makes a guess on how two trees must be shifted to
index a0c00d38787ec406b952fbebd057b83f2cae69b6..24b67d5dea437ef05af2ca78419f16e6ecd12656 100644 (file)
@@ -437,6 +437,13 @@ static int merge_working_tree(struct checkout_opts *opts,
                         */
 
                        add_files_to_cache(NULL, NULL, 0);
+                       /*
+                        * NEEDSWORK: carrying over local changes
+                        * when branches have different end-of-line
+                        * normalization (or clean+smudge rules) is
+                        * a pain; plumb in an option to set
+                        * o.renormalize?
+                        */
                        init_merge_options(&o);
                        o.verbosity = 0;
                        work = write_tree_from_memory(&o);
index d8875d589240e0c78a9e241a7d2bdde1d10ab800..c2d4677fd3db9b4e1360e0c45fdd2d4a110b5629 100644 (file)
@@ -45,6 +45,10 @@ int cmd_merge_recursive(int argc, const char **argv, const char *prefix)
                                o.subtree_shift = "";
                        else if (!prefixcmp(arg+2, "subtree="))
                                o.subtree_shift = arg + 10;
+                       else if (!strcmp(arg+2, "renormalize"))
+                               o.renormalize = 1;
+                       else if (!strcmp(arg+2, "no-renormalize"))
+                               o.renormalize = 0;
                        else
                                die("Unknown option %s", arg);
                        continue;
index b836e9c68b3c10fcc2575041c35743967d77827a..037cd47e7016c24815841b69e77394520f4731c6 100644 (file)
@@ -54,6 +54,7 @@ static size_t use_strategies_nr, use_strategies_alloc;
 static const char **xopts;
 static size_t xopts_nr, xopts_alloc;
 static const char *branch;
+static int option_renormalize;
 static int verbosity;
 static int allow_rerere_auto;
 
@@ -503,9 +504,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
                return git_config_string(&pull_octopus, k, v);
        else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary"))
                option_log = git_config_bool(k, v);
-       else if (!strcmp(k, "merge.renormalize")) {
-               merge_renormalize = git_config_bool(k, v);
-       }
+       else if (!strcmp(k, "merge.renormalize"))
+               option_renormalize = git_config_bool(k, v);
        return git_diff_ui_config(k, v, cb);
 }
 
@@ -627,6 +627,11 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                if (!strcmp(strategy, "subtree"))
                        o.subtree_shift = "";
 
+               o.renormalize = option_renormalize;
+
+               /*
+                * NEEDSWORK: merge with table in builtin/merge-recursive
+                */
                for (x = 0; x < xopts_nr; x++) {
                        if (!strcmp(xopts[x], "ours"))
                                o.recursive_variant = MERGE_RECURSIVE_OURS;
@@ -636,6 +641,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common,
                                o.subtree_shift = "";
                        else if (!prefixcmp(xopts[x], "subtree="))
                                o.subtree_shift = xopts[x]+8;
+                       else if (!strcmp(xopts[x], "renormalize"))
+                               o.renormalize = 1;
+                       else if (!strcmp(xopts[x], "no-renormalize"))
+                               o.renormalize = 0;
                        else
                                die("Unknown option for merge-recursive: -X%s", xopts[x]);
                }
@@ -819,7 +828,7 @@ static int finish_automerge(struct commit_list *common,
        return 0;
 }
 
-static int suggest_conflicts(void)
+static int suggest_conflicts(int renormalizing)
 {
        FILE *fp;
        int pos;
@@ -1304,5 +1313,5 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
                        "stopped before committing as requested\n");
                return 0;
        } else
-               return suggest_conflicts();
+               return suggest_conflicts(option_renormalize);
 }
index 853e9e406c7fe258c39fa7e5c53f15f739a935b1..11132533c6d597ee6f920f5e78e8171cc5f30a44 100644 (file)
@@ -318,6 +318,13 @@ static void do_recursive_merge(struct commit *base, struct commit *next,
        index_fd = hold_locked_index(&index_lock, 1);
 
        read_cache();
+
+       /*
+        * NEEDSWORK: cherry-picking between branches with
+        * different end-of-line normalization is a pain;
+        * plumb in an option to set o.renormalize?
+        * (or better: arbitrary -X options)
+        */
        init_merge_options(&o);
        o.ancestor = base ? base_label : "(empty tree)";
        o.branch1 = "HEAD";
diff --git a/cache.h b/cache.h
index ed73da883ffdfd031c799355a27eb6bf2d73cae3..aa725b0d3168e93001a96979fd8e29c6c7910f3a 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -551,7 +551,6 @@ extern int read_replace_refs;
 extern int fsync_object_files;
 extern int core_preload_index;
 extern int core_apply_sparse_checkout;
-extern int merge_renormalize;
 
 enum safe_crlf {
        SAFE_CRLF_FALSE = 0,
index 81a36824f03203e41702d9df3ee9c1658f1af7e4..83d38d3c2354e8582d5af91c6d529a2f2836dc2c 100644 (file)
@@ -53,7 +53,6 @@ enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
 char *notes_ref_name;
 int grafts_replace_parents = 1;
 int core_apply_sparse_checkout;
-int merge_renormalize;
 
 /* Parallel index stat data preload? */
 int core_preload_index = 0;
index 23f7a4d139b4ed590113727cd196c7668085542f..762b5494d216b6a3cfe7e79847071e61d9669732 100644 (file)
@@ -1486,7 +1486,7 @@ void init_merge_options(struct merge_options *o)
        o->buffer_output = 1;
        o->diff_rename_limit = -1;
        o->merge_rename_limit = -1;
-       o->renormalize = merge_renormalize;
+       o->renormalize = 0;
        git_config(merge_recursive_config, o);
        if (getenv("GIT_MERGE_VERBOSITY"))
                o->verbosity =