Permalink
Browse files

add status config and command line options for rename detection

Add a new config status.renames setting to enable turning off rename detection
during status.  This setting will default to the value of diff.renames.

Add a new config status.renamelimit setting to to enable bounding the time spent
finding out inexact renames during status.  This setting will default to the
value of diff.renamelimit.

Add status --no-renames command line option that enables overriding the config
setting from the command line. Add --find-renames[=<n>] to enable detecting
renames and optionaly setting the similarity index from the command line.

Origional-Patch-by: Alejandro Pauly <alpauly@microsoft.com>
Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
  • Loading branch information...
benpeart committed Jan 25, 2017
1 parent a92ae92 commit aa977d29643a26bd1de2479a0fcb753fb944c86b
Showing with 173 additions and 2 deletions.
  1. +9 −0 Documentation/config.txt
  2. +57 −0 builtin/commit.c
  3. +1 −1 diff.c
  4. +1 −0 diff.h
  5. +90 −0 t/t7525-status-rename.sh
  6. +12 −0 wt-status.c
  7. +3 −1 wt-status.h
View
@@ -3119,6 +3119,15 @@ status.displayCommentPrefix::
behavior of linkgit:git-status[1] in Git 1.8.4 and previous.
Defaults to false.
status.renameLimit::
The number of files to consider when performing rename detection;
if not specified, defaults to the value of diff.renameLimit.
status.renames::
Whether and how Git detects renames. If set to "false",
rename detection is disabled. If set to "true", basic rename
detection is enabled. Defaults to the value of diff.renames.
status.showStash::
If set to true, linkgit:git-status[1] will display the number of
entries currently stashed away.
View
@@ -109,6 +109,10 @@ static int have_option_m;
static struct strbuf message = STRBUF_INIT;
static enum wt_status_format status_format = STATUS_FORMAT_UNSPECIFIED;
static int diff_detect_rename = -1;
static int status_detect_rename = -1;
static int diff_rename_limit = -1;
static int status_rename_limit = -1;
static int opt_parse_porcelain(const struct option *opt, const char *arg, int unset)
{
@@ -143,6 +147,16 @@ static int opt_parse_m(const struct option *opt, const char *arg, int unset)
return 0;
}
static int opt_parse_rename_score(const struct option *opt, const char *arg, int unset)
{
const char **value = opt->value;
if (arg != NULL && *arg == '=')
arg = arg + 1;
*value = arg;
return 0;
}
static void determine_whence(struct wt_status *s)
{
if (file_exists(git_path_merge_head()))
@@ -1259,11 +1273,29 @@ static int git_status_config(const char *k, const char *v, void *cb)
return error(_("Invalid untracked files mode '%s'"), v);
return 0;
}
if (!strcmp(k, "diff.renamelimit")) {
diff_rename_limit = git_config_int(k, v);
return 0;
}
if (!strcmp(k, "status.renamelimit")) {
status_rename_limit = git_config_int(k, v);
return 0;
}
if (!strcmp(k, "diff.renames")) {
diff_detect_rename = git_config_rename(k, v);
return 0;
}
if (!strcmp(k, "status.renames")) {
status_detect_rename = git_config_rename(k, v);
return 0;
}
return git_diff_ui_config(k, v, NULL);
}
int cmd_status(int argc, const char **argv, const char *prefix)
{
static int no_renames = -1;
static const char *rename_score_arg = (const char *)-1;
static struct wt_status s;
int fd;
struct object_id oid;
@@ -1297,6 +1329,10 @@ int cmd_status(int argc, const char **argv, const char *prefix)
N_("ignore changes to submodules, optional when: all, dirty, untracked. (Default: all)"),
PARSE_OPT_OPTARG, NULL, (intptr_t)"all" },
OPT_COLUMN(0, "column", &s.colopts, N_("list untracked files in columns")),
OPT_BOOL(0, "no-renames", &no_renames, N_("do not detect renames")),
{ OPTION_CALLBACK, 'M', "find-renames", &rename_score_arg,
N_("n"), N_("detect renames, optionally set similarity index"),
PARSE_OPT_OPTARG, opt_parse_rename_score },
OPT_END(),
};
@@ -1336,6 +1372,27 @@ int cmd_status(int argc, const char **argv, const char *prefix)
s.ignore_submodule_arg = ignore_submodule_arg;
s.status_format = status_format;
s.verbose = verbose;
s.detect_rename = no_renames >= 0 ? !no_renames :
status_detect_rename >= 0 ? status_detect_rename :
diff_detect_rename >= 0 ? diff_detect_rename :
s.detect_rename;
if ((intptr_t)rename_score_arg != -1) {
s.detect_rename = DIFF_DETECT_RENAME;
if (rename_score_arg)
s.rename_score = parse_rename_score(&rename_score_arg);
}
s.rename_limit = status_rename_limit >= 0 ? status_rename_limit :
diff_rename_limit >= 0 ? diff_rename_limit :
s.rename_limit;
/*
* We do not have logic to handle the detection of copies. In
* fact, it may not even make sense to add such logic: would we
* really want a change to a base file to be propagated through
* multiple other files by a merge?
*/
if (s.detect_rename > DIFF_DETECT_RENAME)
s.detect_rename = DIFF_DETECT_RENAME;
wt_status_collect(&s);
View
2 diff.c
@@ -177,7 +177,7 @@ static int parse_submodule_params(struct diff_options *options, const char *valu
return 0;
}
static int git_config_rename(const char *var, const char *value)
int git_config_rename(const char *var, const char *value)
{
if (!value)
return DIFF_DETECT_RENAME;
View
1 diff.h
@@ -324,6 +324,7 @@ extern int git_diff_ui_config(const char *var, const char *value, void *cb);
extern void diff_setup(struct diff_options *);
extern int diff_opt_parse(struct diff_options *, const char **, int, const char *);
extern void diff_setup_done(struct diff_options *);
extern int git_config_rename(const char *var, const char *value);
#define DIFF_DETECT_RENAME 1
#define DIFF_DETECT_COPY 2
View
@@ -0,0 +1,90 @@
#!/bin/sh
test_description='git status rename detection options'
. ./test-lib.sh
test_expect_success 'setup' '
echo 1 >original &&
git add . &&
git commit -m"Adding original file." &&
mv original renamed &&
echo 2 >> renamed &&
git add .
'
cat >.gitignore <<\EOF
.gitignore
expect*
actual*
EOF
test_expect_success 'status no-options' '
git status >actual &&
test_i18ngrep "renamed:" actual
'
test_expect_success 'status --no-renames' '
git status --no-renames >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status.renames inherits from diff.renames false' '
git -c diff.renames=false status >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status.renames inherits from diff.renames true' '
git -c diff.renames=true status >actual &&
test_i18ngrep "renamed:" actual
'
test_expect_success 'status.renames overrides diff.renames false' '
git -c diff.renames=true -c status.renames=false status >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status.renames overrides from diff.renames true' '
git -c diff.renames=false -c status.renames=true status >actual &&
test_i18ngrep "renamed:" actual
'
test_expect_success 'status status.renames=false' '
git -c status.renames=false status >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status status.renames=true' '
git -c status.renames=true status >actual &&
test_i18ngrep "renamed:" actual
'
test_expect_success 'status config overriden' '
git -c status.renames=true status --no-renames >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status score=100%' '
git status -M=100% >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual &&
git status --find-rename=100% >actual &&
test_i18ngrep "deleted:" actual &&
test_i18ngrep "new file:" actual
'
test_expect_success 'status score=01%' '
git status -M=01% >actual &&
test_i18ngrep "renamed:" actual &&
git status --find-rename=01% >actual &&
test_i18ngrep "renamed:" actual
'
test_done
View
@@ -138,6 +138,9 @@ void wt_status_prepare(struct wt_status *s)
s->show_stash = 0;
s->ahead_behind_flags = AHEAD_BEHIND_UNSPECIFIED;
s->display_comment_prefix = 0;
s->detect_rename = -1;
s->rename_score = -1;
s->rename_limit = -1;
}
static void wt_longstatus_print_unmerged_header(struct wt_status *s)
@@ -592,6 +595,9 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)
}
rev.diffopt.format_callback = wt_status_collect_changed_cb;
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename;
rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit;
rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score;
copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_files(&rev, 0);
}
@@ -625,6 +631,9 @@ static void wt_status_collect_changes_index(struct wt_status *s)
rev.diffopt.output_format |= DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = wt_status_collect_updated_cb;
rev.diffopt.format_callback_data = s;
rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename;
rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit;
rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score;
copy_pathspec(&rev.prune_data, &s->pathspec);
run_diff_index(&rev, 1);
}
@@ -982,6 +991,9 @@ static void wt_longstatus_print_verbose(struct wt_status *s)
setup_revisions(0, NULL, &rev, &opt);
rev.diffopt.output_format |= DIFF_FORMAT_PATCH;
rev.diffopt.detect_rename = s->detect_rename >= 0 ? s->detect_rename : rev.diffopt.detect_rename;
rev.diffopt.rename_limit = s->rename_limit >= 0 ? s->rename_limit : rev.diffopt.rename_limit;
rev.diffopt.rename_score = s->rename_score >= 0 ? s->rename_score : rev.diffopt.rename_score;
rev.diffopt.file = s->fp;
rev.diffopt.close_file = 0;
/*
View
@@ -89,7 +89,9 @@ struct wt_status {
int show_stash;
int hints;
enum ahead_behind_flags ahead_behind_flags;
int detect_rename;
int rename_score;
int rename_limit;
enum wt_status_format status_format;
unsigned char sha1_commit[GIT_MAX_RAWSZ]; /* when not Initial */

0 comments on commit aa977d2

Please sign in to comment.