Teach 'add -p', 'add -i', 'checkout -p', 'commit --interactive', and
'reset -p' a new --patience option to use the slower “patience diff”
algorithm to produce diffs that can be more sensibly split up.

The 'add -e' command is not affected; that will have to wait for a
later patch.

This patch is not intended for mainline git yet, since it leaves the
man pages out of date.

Signed-off-by: Jonathan Nieder <[email protected]>
---
It would also be nice to add the new switch to the test suite.

 builtin-add.c      |   16 ++++++++++++----
 builtin-checkout.c |   14 +++++++++-----
 builtin-commit.c   |    5 +++--
 builtin-reset.c    |   10 ++++++----
 commit.h           |    5 +++--
 5 files changed, 33 insertions(+), 17 deletions(-)

diff --git a/builtin-add.c b/builtin-add.c
index 2705f8d..72d116f 100644
--- a/builtin-add.c
+++ b/builtin-add.c
@@ -208,7 +208,7 @@ static const char **validate_pathspec(int argc, const char 
**argv, const char *p
 }
 
 int run_add_interactive(const char *revision, const char *patch_mode,
-                       const char **pathspec)
+                       int patience, const char **pathspec)
 {
        int status, ac, pc = 0;
        const char **args;
@@ -217,9 +217,13 @@ int run_add_interactive(const char *revision, const char 
*patch_mode,
                while (pathspec[pc])
                        pc++;
 
-       args = xcalloc(sizeof(const char *), (pc + 5));
+       args = xcalloc(sizeof(const char *),
+               3 + (patch_mode ? 1 : 0) + (patience ? 1 : 0) +
+               (revision ? 1 : 0) + pc);
        ac = 0;
        args[ac++] = "add--interactive";
+       if (patience)
+               args[ac++] = "--patience";
        if (patch_mode)
                args[ac++] = patch_mode;
        if (revision)
@@ -236,7 +240,8 @@ int run_add_interactive(const char *revision, const char 
*patch_mode,
        return status;
 }
 
-int interactive_add(int argc, const char **argv, const char *prefix)
+int interactive_add(int argc, const char **argv,
+                   const char *prefix, int patience)
 {
        const char **pathspec = NULL;
 
@@ -248,6 +253,7 @@ int interactive_add(int argc, const char **argv, const char 
*prefix)
 
        return run_add_interactive(NULL,
                                   patch_interactive ? "--patch" : NULL,
+                                  patience,
                                   pathspec);
 }
 
@@ -303,6 +309,7 @@ static const char ignore_error[] =
 
 static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
 static int ignore_add_errors, addremove, intent_to_add;
+static int patience;
 
 static struct option builtin_add_options[] = {
        OPT__DRY_RUN(&show_only),
@@ -311,6 +318,7 @@ static struct option builtin_add_options[] = {
        OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive 
picking"),
        OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
        OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and 
apply"),
+       OPT_BOOLEAN( 0 , "patience", &patience, "use \"patience diff\" 
algorithm for -i"),
        OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored 
files"),
        OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked 
files"),
        OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact 
that the path will be added later"),
@@ -367,7 +375,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
        if (patch_interactive)
                add_interactive = 1;
        if (add_interactive)
-               exit(interactive_add(argc - 1, argv + 1, prefix));
+               exit(interactive_add(argc - 1, argv + 1, prefix, patience));
 
        if (edit_interactive)
                return(edit_patch(argc, argv, prefix));
diff --git a/builtin-checkout.c b/builtin-checkout.c
index c5ab783..b3bc43e 100644
--- a/builtin-checkout.c
+++ b/builtin-checkout.c
@@ -593,10 +593,11 @@ static int git_checkout_config(const char *var, const 
char *value, void *cb)
        return git_xmerge_config(var, value, cb);
 }
 
-static int interactive_checkout(const char *revision, const char **pathspec,
-                               struct checkout_opts *opts)
+static int interactive_checkout(const char *revision,
+       int patience, const char **pathspec, struct checkout_opts *opts)
 {
-       return run_add_interactive(revision, "--patch=checkout", pathspec);
+       return run_add_interactive(revision, "--patch=checkout",
+                                  patience, pathspec);
 }
 
 struct tracking_name_data {
@@ -643,6 +644,7 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
        struct tree *source_tree = NULL;
        char *conflict_style = NULL;
        int patch_mode = 0;
+       int patience = 0;
        int dwim_new_local_branch = 1;
        struct option options[] = {
                OPT__QUIET(&opts.quiet),
@@ -659,6 +661,7 @@ int cmd_checkout(int argc, const char **argv, const char 
*prefix)
                OPT_STRING(0, "conflict", &conflict_style, "style",
                           "conflict style (merge or diff3)"),
                OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks 
interactively"),
+               OPT_BOOLEAN( 0 , "patience", &patience, "use with -p for 
cleaner hunks"),
                { OPTION_BOOLEAN, 0, "guess", &dwim_new_local_branch, NULL,
                  "second guess 'git checkout no-such-branch'",
                  PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
@@ -813,7 +816,8 @@ no_reference:
                        die("invalid path specification");
 
                if (patch_mode)
-                       return interactive_checkout(new.name, pathspec, &opts);
+                       return interactive_checkout(new.name, patience,
+                                                   pathspec, &opts);
 
                /* Checkout paths */
                if (opts.new_branch) {
@@ -831,7 +835,7 @@ no_reference:
        }
 
        if (patch_mode)
-               return interactive_checkout(new.name, NULL, &opts);
+               return interactive_checkout(new.name, patience, NULL, &opts);
 
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
diff --git a/builtin-commit.c b/builtin-commit.c
index 55676fd..b56b09f 100644
--- a/builtin-commit.c
+++ b/builtin-commit.c
@@ -64,7 +64,7 @@ static const char *logfile, *force_author;
 static const char *template_file;
 static char *edit_message, *use_message;
 static char *author_name, *author_email, *author_date;
-static int all, edit_flag, also, interactive, only, amend, signoff;
+static int all, edit_flag, also, interactive, patience, only, amend, signoff;
 static int quiet, verbose, no_verify, allow_empty, dry_run, renew_authorship;
 static char *untracked_files_arg, *force_date;
 /*
@@ -127,6 +127,7 @@ static struct option builtin_commit_options[] = {
        OPT_BOOLEAN('a', "all", &all, "commit all changed files"),
        OPT_BOOLEAN('i', "include", &also, "add specified files to index for 
commit"),
        OPT_BOOLEAN(0, "interactive", &interactive, "interactively add files"),
+       OPT_BOOLEAN(0, "patience", &patience, "use with --interactive for 
simpler diffs"),
        OPT_BOOLEAN('o', "only", &only, "commit only specified files"),
        OPT_BOOLEAN('n', "no-verify", &no_verify, "bypass pre-commit hook"),
        OPT_BOOLEAN(0, "dry-run", &dry_run, "show what would be committed"),
@@ -278,7 +279,7 @@ static char *prepare_index(int argc, const char **argv, 
const char *prefix, int
        if (is_status)
                refresh_flags |= REFRESH_UNMERGED;
        if (interactive) {
-               if (interactive_add(argc, argv, prefix) != 0)
+               if (interactive_add(argc, argv, prefix, patience) != 0)
                        die("interactive add failed");
                if (read_cache_preload(NULL) < 0)
                        die("index file corrupt");
diff --git a/builtin-reset.c b/builtin-reset.c
index 0f5022e..3155bab 100644
--- a/builtin-reset.c
+++ b/builtin-reset.c
@@ -163,14 +163,15 @@ static void update_index_from_diff(struct 
diff_queue_struct *q,
 }
 
 static int interactive_reset(const char *revision, const char **argv,
-                            const char *prefix)
+                            const char *prefix, int patience)
 {
        const char **pathspec = NULL;
 
        if (*argv)
                pathspec = get_pathspec(prefix, argv);
 
-       return run_add_interactive(revision, "--patch=reset", pathspec);
+       return run_add_interactive(revision, "--patch=reset",
+                                  patience, pathspec);
 }
 
 static int read_from_tree(const char *prefix, const char **argv,
@@ -214,7 +215,7 @@ static void prepend_reflog_action(const char *action, char 
*buf, size_t size)
 int cmd_reset(int argc, const char **argv, const char *prefix)
 {
        int i = 0, reset_type = NONE, update_ref_status = 0, quiet = 0;
-       int patch_mode = 0;
+       int patch_mode = 0, patience = 0;
        const char *rev = "HEAD";
        unsigned char sha1[20], *orig = NULL, sha1_orig[20],
                                *old_orig = NULL, sha1_old_orig[20];
@@ -230,6 +231,7 @@ int cmd_reset(int argc, const char **argv, const char 
*prefix)
                OPT_SET_INT(0, "merge", &reset_type,
                                "reset HEAD, index and working tree", MERGE),
                OPT_BOOLEAN('p', "patch", &patch_mode, "select hunks 
interactively"),
+               OPT_BOOLEAN(0, "patience", &patience, "use with -p for cleaner 
hunks"),
                OPT_END()
        };
 
@@ -286,7 +288,7 @@ int cmd_reset(int argc, const char **argv, const char 
*prefix)
        if (patch_mode) {
                if (reset_type != NONE)
                        die("--patch is incompatible with --{hard,mixed,soft}");
-               return interactive_reset(rev, argv + i, prefix);
+               return interactive_reset(rev, argv + i, prefix, patience);
        }
 
        /* git reset tree [--] paths... can be used to
diff --git a/commit.h b/commit.h
index 3cf5166..47c2cb5 100644
--- a/commit.h
+++ b/commit.h
@@ -147,9 +147,10 @@ extern struct commit_list *get_shallow_commits(struct 
object_array *heads,
 int is_descendant_of(struct commit *, struct commit_list *);
 int in_merge_bases(struct commit *, struct commit **, int);
 
-extern int interactive_add(int argc, const char **argv, const char *prefix);
+extern int interactive_add(int argc, const char **argv, const char *prefix,
+                          int patience);
 extern int run_add_interactive(const char *revision, const char *patch_mode,
-                              const char **pathspec);
+                              int patience, const char **pathspec);
 
 static inline int single_parent(struct commit *commit)
 {
-- 
1.7.0.183.g328ba




-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to