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]

