Merge branch 'sb/diff-color-move'
"git diff" has been taught to optionally paint new lines that are the same as deleted lines elsewhere differently from genuinely new lines. * sb/diff-color-move: (25 commits) diff: document the new --color-moved setting diff.c: add dimming to moved line detection diff.c: color moved lines differently, plain mode diff.c: color moved lines differently diff.c: buffer all output if asked to diff.c: emit_diff_symbol learns about DIFF_SYMBOL_SUMMARY diff.c: emit_diff_symbol learns about DIFF_SYMBOL_STAT_SEP diff.c: convert word diffing to use emit_diff_symbol diff.c: convert show_stats to use emit_diff_symbol diff.c: convert emit_binary_diff_body to use emit_diff_symbol submodule.c: migrate diff output to use emit_diff_symbol diff.c: emit_diff_symbol learns DIFF_SYMBOL_REWRITE_DIFF diff.c: emit_diff_symbol learns about DIFF_SYMBOL_BINARY_FILES diff.c: emit_diff_symbol learns DIFF_SYMBOL_HEADER diff.c: emit_diff_symbol learns DIFF_SYMBOL_FILEPAIR_{PLUS, MINUS} diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_INCOMPLETE diff.c: emit_diff_symbol learns DIFF_SYMBOL_WORDS[_PORCELAIN] diff.c: migrate emit_line_checked to use emit_diff_symbol diff.c: emit_diff_symbol learns DIFF_SYMBOL_NO_LF_EOF diff.c: emit_diff_symbol learns DIFF_SYMBOL_CONTEXT_FRAGINFO ...
This commit is contained in:
commit
b6c4058f97
@ -1077,14 +1077,25 @@ This does not affect linkgit:git-format-patch[1] or the
|
||||
'git-diff-{asterisk}' plumbing commands. Can be overridden on the
|
||||
command line with the `--color[=<when>]` option.
|
||||
|
||||
diff.colorMoved::
|
||||
If set to either a valid `<mode>` or a true value, moved lines
|
||||
in a diff are colored differently, for details of valid modes
|
||||
see '--color-moved' in linkgit:git-diff[1]. If simply set to
|
||||
true the default color mode will be used. When set to false,
|
||||
moved lines are not colored.
|
||||
|
||||
color.diff.<slot>::
|
||||
Use customized color for diff colorization. `<slot>` specifies
|
||||
which part of the patch to use the specified color, and is one
|
||||
of `context` (context text - `plain` is a historical synonym),
|
||||
`meta` (metainformation), `frag`
|
||||
(hunk header), 'func' (function in hunk header), `old` (removed lines),
|
||||
`new` (added lines), `commit` (commit headers), or `whitespace`
|
||||
(highlighting whitespace errors).
|
||||
`new` (added lines), `commit` (commit headers), `whitespace`
|
||||
(highlighting whitespace errors), `oldMoved` (deleted lines),
|
||||
`newMoved` (added lines), `oldMovedDimmed`, `oldMovedAlternative`,
|
||||
`oldMovedAlternativeDimmed`, `newMovedDimmed`, `newMovedAlternative`
|
||||
and `newMovedAlternativeDimmed` (See the '<mode>'
|
||||
setting of '--color-moved' in linkgit:git-diff[1] for details).
|
||||
|
||||
color.decorate.<slot>::
|
||||
Use customized color for 'git log --decorate' output. `<slot>` is one
|
||||
|
@ -231,6 +231,42 @@ ifdef::git-diff[]
|
||||
endif::git-diff[]
|
||||
It is the same as `--color=never`.
|
||||
|
||||
--color-moved[=<mode>]::
|
||||
Moved lines of code are colored differently.
|
||||
ifdef::git-diff[]
|
||||
It can be changed by the `diff.colorMoved` configuration setting.
|
||||
endif::git-diff[]
|
||||
The <mode> defaults to 'no' if the option is not given
|
||||
and to 'zebra' if the option with no mode is given.
|
||||
The mode must be one of:
|
||||
+
|
||||
--
|
||||
no::
|
||||
Moved lines are not highlighted.
|
||||
default::
|
||||
Is a synonym for `zebra`. This may change to a more sensible mode
|
||||
in the future.
|
||||
plain::
|
||||
Any line that is added in one location and was removed
|
||||
in another location will be colored with 'color.diff.newMoved'.
|
||||
Similarly 'color.diff.oldMoved' will be used for removed lines
|
||||
that are added somewhere else in the diff. This mode picks up any
|
||||
moved line, but it is not very useful in a review to determine
|
||||
if a block of code was moved without permutation.
|
||||
zebra::
|
||||
Blocks of moved code are detected greedily. The detected blocks are
|
||||
painted using either the 'color.diff.{old,new}Moved' color or
|
||||
'color.diff.{old,new}MovedAlternative'. The change between
|
||||
the two colors indicates that a new block was detected. If there
|
||||
are fewer than 3 adjacent moved lines, they are not marked up
|
||||
as moved, but the regular colors 'color.diff.{old,new}' will be
|
||||
used.
|
||||
dimmed_zebra::
|
||||
Similar to 'zebra', but additional dimming of uninteresting parts
|
||||
of moved code is performed. The bordering lines of two adjacent
|
||||
blocks are considered interesting, the rest is uninteresting.
|
||||
--
|
||||
|
||||
--word-diff[=<mode>]::
|
||||
Show a word diff, using the <mode> to delimit changed words.
|
||||
By default, words are delimited by whitespace; see
|
||||
|
2
cache.h
2
cache.h
@ -1955,6 +1955,8 @@ void shift_tree_by(const struct object_id *, const struct object_id *, struct ob
|
||||
#define WS_TRAILING_SPACE (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
|
||||
#define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
|
||||
#define WS_TAB_WIDTH_MASK 077
|
||||
/* All WS_* -- when extended, adapt diff.c emit_symbol */
|
||||
#define WS_RULE_MASK 07777
|
||||
extern unsigned whitespace_rule_cfg;
|
||||
extern unsigned whitespace_rule(const char *);
|
||||
extern unsigned parse_whitespace_rule(const char *);
|
||||
|
2
color.h
2
color.h
@ -42,6 +42,8 @@ struct strbuf;
|
||||
#define GIT_COLOR_BG_BLUE "\033[44m"
|
||||
#define GIT_COLOR_BG_MAGENTA "\033[45m"
|
||||
#define GIT_COLOR_BG_CYAN "\033[46m"
|
||||
#define GIT_COLOR_FAINT "\033[2m"
|
||||
#define GIT_COLOR_FAINT_ITALIC "\033[2;3m"
|
||||
|
||||
/* A special value meaning "no color selected" */
|
||||
#define GIT_COLOR_NIL "NIL"
|
||||
|
39
diff.h
39
diff.h
@ -148,9 +148,9 @@ struct diff_options {
|
||||
int abbrev;
|
||||
int ita_invisible_in_index;
|
||||
/* white-space error highlighting */
|
||||
#define WSEH_NEW 1
|
||||
#define WSEH_CONTEXT 2
|
||||
#define WSEH_OLD 4
|
||||
#define WSEH_NEW (1<<12)
|
||||
#define WSEH_CONTEXT (1<<13)
|
||||
#define WSEH_OLD (1<<14)
|
||||
unsigned ws_error_highlight;
|
||||
const char *prefix;
|
||||
int prefix_length;
|
||||
@ -186,8 +186,27 @@ struct diff_options {
|
||||
void *output_prefix_data;
|
||||
|
||||
int diff_path_counter;
|
||||
|
||||
struct emitted_diff_symbols *emitted_symbols;
|
||||
enum {
|
||||
COLOR_MOVED_NO = 0,
|
||||
COLOR_MOVED_PLAIN = 1,
|
||||
COLOR_MOVED_ZEBRA = 2,
|
||||
COLOR_MOVED_ZEBRA_DIM = 3,
|
||||
} color_moved;
|
||||
#define COLOR_MOVED_DEFAULT COLOR_MOVED_ZEBRA
|
||||
#define COLOR_MOVED_MIN_BLOCK_LENGTH 3
|
||||
};
|
||||
|
||||
void diff_emit_submodule_del(struct diff_options *o, const char *line);
|
||||
void diff_emit_submodule_add(struct diff_options *o, const char *line);
|
||||
void diff_emit_submodule_untracked(struct diff_options *o, const char *path);
|
||||
void diff_emit_submodule_modified(struct diff_options *o, const char *path);
|
||||
void diff_emit_submodule_header(struct diff_options *o, const char *header);
|
||||
void diff_emit_submodule_error(struct diff_options *o, const char *err);
|
||||
void diff_emit_submodule_pipethrough(struct diff_options *o,
|
||||
const char *line, int len);
|
||||
|
||||
enum color_diff {
|
||||
DIFF_RESET = 0,
|
||||
DIFF_CONTEXT = 1,
|
||||
@ -197,7 +216,15 @@ enum color_diff {
|
||||
DIFF_FILE_NEW = 5,
|
||||
DIFF_COMMIT = 6,
|
||||
DIFF_WHITESPACE = 7,
|
||||
DIFF_FUNCINFO = 8
|
||||
DIFF_FUNCINFO = 8,
|
||||
DIFF_FILE_OLD_MOVED = 9,
|
||||
DIFF_FILE_OLD_MOVED_ALT = 10,
|
||||
DIFF_FILE_OLD_MOVED_DIM = 11,
|
||||
DIFF_FILE_OLD_MOVED_ALT_DIM = 12,
|
||||
DIFF_FILE_NEW_MOVED = 13,
|
||||
DIFF_FILE_NEW_MOVED_ALT = 14,
|
||||
DIFF_FILE_NEW_MOVED_DIM = 15,
|
||||
DIFF_FILE_NEW_MOVED_ALT_DIM = 16
|
||||
};
|
||||
const char *diff_get_color(int diff_use_color, enum color_diff ix);
|
||||
#define diff_get_color_opt(o, ix) \
|
||||
@ -396,8 +423,8 @@ extern int parse_rename_score(const char **cp_p);
|
||||
|
||||
extern long parse_algorithm_value(const char *value);
|
||||
|
||||
extern int print_stat_summary(FILE *fp, int files,
|
||||
int insertions, int deletions);
|
||||
extern void print_stat_summary(FILE *fp, int files,
|
||||
int insertions, int deletions);
|
||||
extern void setup_diff_pager(struct diff_options *);
|
||||
|
||||
#endif /* DIFF_H */
|
||||
|
84
submodule.c
84
submodule.c
@ -478,9 +478,7 @@ static int prepare_submodule_summary(struct rev_info *rev, const char *path,
|
||||
return prepare_revision_walk(rev);
|
||||
}
|
||||
|
||||
static void print_submodule_summary(struct rev_info *rev, FILE *f,
|
||||
const char *line_prefix,
|
||||
const char *del, const char *add, const char *reset)
|
||||
static void print_submodule_summary(struct rev_info *rev, struct diff_options *o)
|
||||
{
|
||||
static const char format[] = " %m %s";
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
@ -491,18 +489,12 @@ static void print_submodule_summary(struct rev_info *rev, FILE *f,
|
||||
ctx.date_mode = rev->date_mode;
|
||||
ctx.output_encoding = get_log_output_encoding();
|
||||
strbuf_setlen(&sb, 0);
|
||||
strbuf_addstr(&sb, line_prefix);
|
||||
if (commit->object.flags & SYMMETRIC_LEFT) {
|
||||
if (del)
|
||||
strbuf_addstr(&sb, del);
|
||||
}
|
||||
else if (add)
|
||||
strbuf_addstr(&sb, add);
|
||||
format_commit_message(commit, format, &sb, &ctx);
|
||||
if (reset)
|
||||
strbuf_addstr(&sb, reset);
|
||||
strbuf_addch(&sb, '\n');
|
||||
fprintf(f, "%s", sb.buf);
|
||||
if (commit->object.flags & SYMMETRIC_LEFT)
|
||||
diff_emit_submodule_del(o, sb.buf);
|
||||
else
|
||||
diff_emit_submodule_add(o, sb.buf);
|
||||
}
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
@ -529,11 +521,9 @@ void prepare_submodule_repo_env(struct argv_array *out)
|
||||
* attempt to lookup both the left and right commits and put them into the
|
||||
* left and right pointers.
|
||||
*/
|
||||
static void show_submodule_header(FILE *f, const char *path,
|
||||
const char *line_prefix,
|
||||
static void show_submodule_header(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule, const char *meta,
|
||||
const char *reset,
|
||||
unsigned dirty_submodule,
|
||||
struct commit **left, struct commit **right,
|
||||
struct commit_list **merge_bases)
|
||||
{
|
||||
@ -542,11 +532,10 @@ static void show_submodule_header(FILE *f, const char *path,
|
||||
int fast_forward = 0, fast_backward = 0;
|
||||
|
||||
if (dirty_submodule & DIRTY_SUBMODULE_UNTRACKED)
|
||||
fprintf(f, "%sSubmodule %s contains untracked content\n",
|
||||
line_prefix, path);
|
||||
diff_emit_submodule_untracked(o, path);
|
||||
|
||||
if (dirty_submodule & DIRTY_SUBMODULE_MODIFIED)
|
||||
fprintf(f, "%sSubmodule %s contains modified content\n",
|
||||
line_prefix, path);
|
||||
diff_emit_submodule_modified(o, path);
|
||||
|
||||
if (is_null_oid(one))
|
||||
message = "(new submodule)";
|
||||
@ -588,31 +577,29 @@ static void show_submodule_header(FILE *f, const char *path,
|
||||
}
|
||||
|
||||
output_header:
|
||||
strbuf_addf(&sb, "%s%sSubmodule %s ", line_prefix, meta, path);
|
||||
strbuf_addf(&sb, "Submodule %s ", path);
|
||||
strbuf_add_unique_abbrev(&sb, one->hash, DEFAULT_ABBREV);
|
||||
strbuf_addstr(&sb, (fast_backward || fast_forward) ? ".." : "...");
|
||||
strbuf_add_unique_abbrev(&sb, two->hash, DEFAULT_ABBREV);
|
||||
if (message)
|
||||
strbuf_addf(&sb, " %s%s\n", message, reset);
|
||||
strbuf_addf(&sb, " %s\n", message);
|
||||
else
|
||||
strbuf_addf(&sb, "%s:%s\n", fast_backward ? " (rewind)" : "", reset);
|
||||
fwrite(sb.buf, sb.len, 1, f);
|
||||
strbuf_addf(&sb, "%s:\n", fast_backward ? " (rewind)" : "");
|
||||
diff_emit_submodule_header(o, sb.buf);
|
||||
|
||||
strbuf_release(&sb);
|
||||
}
|
||||
|
||||
void show_submodule_summary(FILE *f, const char *path,
|
||||
const char *line_prefix,
|
||||
void show_submodule_summary(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule, const char *meta,
|
||||
const char *del, const char *add, const char *reset)
|
||||
unsigned dirty_submodule)
|
||||
{
|
||||
struct rev_info rev;
|
||||
struct commit *left = NULL, *right = NULL;
|
||||
struct commit_list *merge_bases = NULL;
|
||||
|
||||
show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
|
||||
meta, reset, &left, &right, &merge_bases);
|
||||
show_submodule_header(o, path, one, two, dirty_submodule,
|
||||
&left, &right, &merge_bases);
|
||||
|
||||
/*
|
||||
* If we don't have both a left and a right pointer, there is no
|
||||
@ -624,11 +611,11 @@ void show_submodule_summary(FILE *f, const char *path,
|
||||
|
||||
/* Treat revision walker failure the same as missing commits */
|
||||
if (prepare_submodule_summary(&rev, path, left, right, merge_bases)) {
|
||||
fprintf(f, "%s(revision walker failed)\n", line_prefix);
|
||||
diff_emit_submodule_error(o, "(revision walker failed)\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
print_submodule_summary(&rev, f, line_prefix, del, add, reset);
|
||||
print_submodule_summary(&rev, o);
|
||||
|
||||
out:
|
||||
if (merge_bases)
|
||||
@ -637,21 +624,18 @@ out:
|
||||
clear_commit_marks(right, ~0);
|
||||
}
|
||||
|
||||
void show_submodule_inline_diff(FILE *f, const char *path,
|
||||
const char *line_prefix,
|
||||
void show_submodule_inline_diff(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule, const char *meta,
|
||||
const char *del, const char *add, const char *reset,
|
||||
const struct diff_options *o)
|
||||
unsigned dirty_submodule)
|
||||
{
|
||||
const struct object_id *old = &empty_tree_oid, *new = &empty_tree_oid;
|
||||
struct commit *left = NULL, *right = NULL;
|
||||
struct commit_list *merge_bases = NULL;
|
||||
struct strbuf submodule_dir = STRBUF_INIT;
|
||||
struct child_process cp = CHILD_PROCESS_INIT;
|
||||
struct strbuf sb = STRBUF_INIT;
|
||||
|
||||
show_submodule_header(f, path, line_prefix, one, two, dirty_submodule,
|
||||
meta, reset, &left, &right, &merge_bases);
|
||||
show_submodule_header(o, path, one, two, dirty_submodule,
|
||||
&left, &right, &merge_bases);
|
||||
|
||||
/* We need a valid left and right commit to display a difference */
|
||||
if (!(left || is_null_oid(one)) ||
|
||||
@ -663,16 +647,16 @@ void show_submodule_inline_diff(FILE *f, const char *path,
|
||||
if (right)
|
||||
new = two;
|
||||
|
||||
fflush(f);
|
||||
cp.git_cmd = 1;
|
||||
cp.dir = path;
|
||||
cp.out = dup(fileno(f));
|
||||
cp.out = -1;
|
||||
cp.no_stdin = 1;
|
||||
|
||||
/* TODO: other options may need to be passed here. */
|
||||
argv_array_pushl(&cp.args, "diff", "--submodule=diff", NULL);
|
||||
argv_array_pushf(&cp.args, "--color=%s", want_color(o->use_color) ?
|
||||
"always" : "never");
|
||||
|
||||
argv_array_pushf(&cp.args, "--line-prefix=%s", line_prefix);
|
||||
if (DIFF_OPT_TST(o, REVERSE_DIFF)) {
|
||||
argv_array_pushf(&cp.args, "--src-prefix=%s%s/",
|
||||
o->b_prefix, path);
|
||||
@ -695,11 +679,17 @@ void show_submodule_inline_diff(FILE *f, const char *path,
|
||||
argv_array_push(&cp.args, oid_to_hex(new));
|
||||
|
||||
prepare_submodule_repo_env(&cp.env_array);
|
||||
if (run_command(&cp))
|
||||
fprintf(f, "(diff failed)\n");
|
||||
if (start_command(&cp))
|
||||
diff_emit_submodule_error(o, "(diff failed)\n");
|
||||
|
||||
while (strbuf_getwholeline_fd(&sb, cp.out, '\n') != EOF)
|
||||
diff_emit_submodule_pipethrough(o, sb.buf, sb.len);
|
||||
|
||||
if (finish_command(&cp))
|
||||
diff_emit_submodule_error(o, "(diff failed)\n");
|
||||
|
||||
done:
|
||||
strbuf_release(&submodule_dir);
|
||||
strbuf_release(&sb);
|
||||
if (merge_bases)
|
||||
free_commit_list(merge_bases);
|
||||
if (left)
|
||||
|
13
submodule.h
13
submodule.h
@ -66,17 +66,12 @@ extern int parse_submodule_update_strategy(const char *value,
|
||||
struct submodule_update_strategy *dst);
|
||||
extern const char *submodule_strategy_to_string(const struct submodule_update_strategy *s);
|
||||
extern void handle_ignore_submodules_arg(struct diff_options *, const char *);
|
||||
extern void show_submodule_summary(FILE *f, const char *path,
|
||||
const char *line_prefix,
|
||||
extern void show_submodule_summary(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule, const char *meta,
|
||||
const char *del, const char *add, const char *reset);
|
||||
extern void show_submodule_inline_diff(FILE *f, const char *path,
|
||||
const char *line_prefix,
|
||||
unsigned dirty_submodule);
|
||||
extern void show_submodule_inline_diff(struct diff_options *o, const char *path,
|
||||
struct object_id *one, struct object_id *two,
|
||||
unsigned dirty_submodule, const char *meta,
|
||||
const char *del, const char *add, const char *reset,
|
||||
const struct diff_options *opt);
|
||||
unsigned dirty_submodule);
|
||||
/* Check if we want to update any submodule.*/
|
||||
extern int should_update_submodules(void);
|
||||
/*
|
||||
|
@ -972,4 +972,438 @@ test_expect_success 'option overrides diff.wsErrorHighlight' '
|
||||
|
||||
'
|
||||
|
||||
test_expect_success 'detect moved code, complete file' '
|
||||
git reset --hard &&
|
||||
cat <<-\EOF >test.c &&
|
||||
#include<stdio.h>
|
||||
main()
|
||||
{
|
||||
printf("Hello World");
|
||||
}
|
||||
EOF
|
||||
git add test.c &&
|
||||
git commit -m "add main function" &&
|
||||
git mv test.c main.c &&
|
||||
test_config color.diff.oldMoved "normal red" &&
|
||||
test_config color.diff.newMoved "normal green" &&
|
||||
git diff HEAD --color-moved=zebra --no-renames | test_decode_color >actual &&
|
||||
cat >expected <<-\EOF &&
|
||||
<BOLD>diff --git a/main.c b/main.c<RESET>
|
||||
<BOLD>new file mode 100644<RESET>
|
||||
<BOLD>index 0000000..a986c57<RESET>
|
||||
<BOLD>--- /dev/null<RESET>
|
||||
<BOLD>+++ b/main.c<RESET>
|
||||
<CYAN>@@ -0,0 +1,5 @@<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>#include<stdio.h><RESET>
|
||||
<BGREEN>+<RESET><BGREEN>main()<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>{<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>printf("Hello World");<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>}<RESET>
|
||||
<BOLD>diff --git a/test.c b/test.c<RESET>
|
||||
<BOLD>deleted file mode 100644<RESET>
|
||||
<BOLD>index a986c57..0000000<RESET>
|
||||
<BOLD>--- a/test.c<RESET>
|
||||
<BOLD>+++ /dev/null<RESET>
|
||||
<CYAN>@@ -1,5 +0,0 @@<RESET>
|
||||
<BRED>-#include<stdio.h><RESET>
|
||||
<BRED>-main()<RESET>
|
||||
<BRED>-{<RESET>
|
||||
<BRED>-printf("Hello World");<RESET>
|
||||
<BRED>-}<RESET>
|
||||
EOF
|
||||
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'detect malicious moved code, inside file' '
|
||||
test_config color.diff.oldMoved "normal red" &&
|
||||
test_config color.diff.newMoved "normal green" &&
|
||||
test_config color.diff.oldMovedAlternative "blue" &&
|
||||
test_config color.diff.newMovedAlternative "yellow" &&
|
||||
git reset --hard &&
|
||||
cat <<-\EOF >main.c &&
|
||||
#include<stdio.h>
|
||||
int stuff()
|
||||
{
|
||||
printf("Hello ");
|
||||
printf("World\n");
|
||||
}
|
||||
|
||||
int secure_foo(struct user *u)
|
||||
{
|
||||
if (!u->is_allowed_foo)
|
||||
return;
|
||||
foo(u);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo();
|
||||
}
|
||||
EOF
|
||||
cat <<-\EOF >test.c &&
|
||||
#include<stdio.h>
|
||||
int bar()
|
||||
{
|
||||
printf("Hello World, but different\n");
|
||||
}
|
||||
|
||||
int another_function()
|
||||
{
|
||||
bar();
|
||||
}
|
||||
EOF
|
||||
git add main.c test.c &&
|
||||
git commit -m "add main and test file" &&
|
||||
cat <<-\EOF >main.c &&
|
||||
#include<stdio.h>
|
||||
int stuff()
|
||||
{
|
||||
printf("Hello ");
|
||||
printf("World\n");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
foo();
|
||||
}
|
||||
EOF
|
||||
cat <<-\EOF >test.c &&
|
||||
#include<stdio.h>
|
||||
int bar()
|
||||
{
|
||||
printf("Hello World, but different\n");
|
||||
}
|
||||
|
||||
int secure_foo(struct user *u)
|
||||
{
|
||||
foo(u);
|
||||
if (!u->is_allowed_foo)
|
||||
return;
|
||||
}
|
||||
|
||||
int another_function()
|
||||
{
|
||||
bar();
|
||||
}
|
||||
EOF
|
||||
git diff HEAD --no-renames --color-moved=zebra| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/main.c b/main.c<RESET>
|
||||
<BOLD>index 27a619c..7cf9336 100644<RESET>
|
||||
<BOLD>--- a/main.c<RESET>
|
||||
<BOLD>+++ b/main.c<RESET>
|
||||
<CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
|
||||
printf("World\n");<RESET>
|
||||
}<RESET>
|
||||
<RESET>
|
||||
<BRED>-int secure_foo(struct user *u)<RESET>
|
||||
<BRED>-{<RESET>
|
||||
<BLUE>-if (!u->is_allowed_foo)<RESET>
|
||||
<BLUE>-return;<RESET>
|
||||
<BRED>-foo(u);<RESET>
|
||||
<BLUE>-}<RESET>
|
||||
<BLUE>-<RESET>
|
||||
int main()<RESET>
|
||||
{<RESET>
|
||||
foo();<RESET>
|
||||
<BOLD>diff --git a/test.c b/test.c<RESET>
|
||||
<BOLD>index 1dc1d85..2bedec9 100644<RESET>
|
||||
<BOLD>--- a/test.c<RESET>
|
||||
<BOLD>+++ b/test.c<RESET>
|
||||
<CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
|
||||
printf("Hello World, but different\n");<RESET>
|
||||
}<RESET>
|
||||
<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>{<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>foo(u);<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>return;<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>}<RESET>
|
||||
<YELLOW>+<RESET>
|
||||
int another_function()<RESET>
|
||||
{<RESET>
|
||||
bar();<RESET>
|
||||
EOF
|
||||
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'plain moved code, inside file' '
|
||||
test_config color.diff.oldMoved "normal red" &&
|
||||
test_config color.diff.newMoved "normal green" &&
|
||||
test_config color.diff.oldMovedAlternative "blue" &&
|
||||
test_config color.diff.newMovedAlternative "yellow" &&
|
||||
# needs previous test as setup
|
||||
git diff HEAD --no-renames --color-moved=plain| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/main.c b/main.c<RESET>
|
||||
<BOLD>index 27a619c..7cf9336 100644<RESET>
|
||||
<BOLD>--- a/main.c<RESET>
|
||||
<BOLD>+++ b/main.c<RESET>
|
||||
<CYAN>@@ -5,13 +5,6 @@<RESET> <RESET>printf("Hello ");<RESET>
|
||||
printf("World\n");<RESET>
|
||||
}<RESET>
|
||||
<RESET>
|
||||
<BRED>-int secure_foo(struct user *u)<RESET>
|
||||
<BRED>-{<RESET>
|
||||
<BRED>-if (!u->is_allowed_foo)<RESET>
|
||||
<BRED>-return;<RESET>
|
||||
<BRED>-foo(u);<RESET>
|
||||
<BRED>-}<RESET>
|
||||
<BRED>-<RESET>
|
||||
int main()<RESET>
|
||||
{<RESET>
|
||||
foo();<RESET>
|
||||
<BOLD>diff --git a/test.c b/test.c<RESET>
|
||||
<BOLD>index 1dc1d85..2bedec9 100644<RESET>
|
||||
<BOLD>--- a/test.c<RESET>
|
||||
<BOLD>+++ b/test.c<RESET>
|
||||
<CYAN>@@ -4,6 +4,13 @@<RESET> <RESET>int bar()<RESET>
|
||||
printf("Hello World, but different\n");<RESET>
|
||||
}<RESET>
|
||||
<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>int secure_foo(struct user *u)<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>{<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>foo(u);<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>if (!u->is_allowed_foo)<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>return;<RESET>
|
||||
<BGREEN>+<RESET><BGREEN>}<RESET>
|
||||
<BGREEN>+<RESET>
|
||||
int another_function()<RESET>
|
||||
{<RESET>
|
||||
bar();<RESET>
|
||||
EOF
|
||||
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'detect permutations inside moved code -- dimmed_zebra' '
|
||||
git reset --hard &&
|
||||
cat <<-\EOF >lines.txt &&
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
line 7
|
||||
line 8
|
||||
line 9
|
||||
line 10
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
EOF
|
||||
git add lines.txt &&
|
||||
git commit -m "add poetry" &&
|
||||
cat <<-\EOF >lines.txt &&
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
line 7
|
||||
line 8
|
||||
line 9
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 14
|
||||
line 15
|
||||
line 16
|
||||
line 10
|
||||
line 11
|
||||
line 12
|
||||
line 13
|
||||
EOF
|
||||
test_config color.diff.oldMoved "magenta" &&
|
||||
test_config color.diff.newMoved "cyan" &&
|
||||
test_config color.diff.oldMovedAlternative "blue" &&
|
||||
test_config color.diff.newMovedAlternative "yellow" &&
|
||||
test_config color.diff.oldMovedDimmed "normal magenta" &&
|
||||
test_config color.diff.newMovedDimmed "normal cyan" &&
|
||||
test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
|
||||
test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
|
||||
git diff HEAD --no-renames --color-moved=dimmed_zebra| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
|
||||
<BOLD>index 47ea9c3..ba96a38 100644<RESET>
|
||||
<BOLD>--- a/lines.txt<RESET>
|
||||
<BOLD>+++ b/lines.txt<RESET>
|
||||
<CYAN>@@ -1,16 +1,16 @@<RESET>
|
||||
<BMAGENTA>-line 1<RESET>
|
||||
<BMAGENTA>-line 2<RESET>
|
||||
<BMAGENTA>-line 3<RESET>
|
||||
line 4<RESET>
|
||||
line 5<RESET>
|
||||
line 6<RESET>
|
||||
line 7<RESET>
|
||||
line 8<RESET>
|
||||
line 9<RESET>
|
||||
<BCYAN>+<RESET><BCYAN>line 1<RESET>
|
||||
<BCYAN>+<RESET><BCYAN>line 2<RESET>
|
||||
<CYAN>+<RESET><CYAN>line 3<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>line 14<RESET>
|
||||
<BYELLOW>+<RESET><BYELLOW>line 15<RESET>
|
||||
<BYELLOW>+<RESET><BYELLOW>line 16<RESET>
|
||||
line 10<RESET>
|
||||
line 11<RESET>
|
||||
line 12<RESET>
|
||||
line 13<RESET>
|
||||
<BMAGENTA>-line 14<RESET>
|
||||
<BMAGENTA>-line 15<RESET>
|
||||
<BMAGENTA>-line 16<RESET>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'cmd option assumes configured colored-moved' '
|
||||
test_config color.diff.oldMoved "magenta" &&
|
||||
test_config color.diff.newMoved "cyan" &&
|
||||
test_config color.diff.oldMovedAlternative "blue" &&
|
||||
test_config color.diff.newMovedAlternative "yellow" &&
|
||||
test_config color.diff.oldMovedDimmed "normal magenta" &&
|
||||
test_config color.diff.newMovedDimmed "normal cyan" &&
|
||||
test_config color.diff.oldMovedAlternativeDimmed "normal blue" &&
|
||||
test_config color.diff.newMovedAlternativeDimmed "normal yellow" &&
|
||||
test_config diff.colorMoved zebra &&
|
||||
git diff HEAD --no-renames --color-moved| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
|
||||
<BOLD>index 47ea9c3..ba96a38 100644<RESET>
|
||||
<BOLD>--- a/lines.txt<RESET>
|
||||
<BOLD>+++ b/lines.txt<RESET>
|
||||
<CYAN>@@ -1,16 +1,16 @@<RESET>
|
||||
<MAGENTA>-line 1<RESET>
|
||||
<MAGENTA>-line 2<RESET>
|
||||
<MAGENTA>-line 3<RESET>
|
||||
line 4<RESET>
|
||||
line 5<RESET>
|
||||
line 6<RESET>
|
||||
line 7<RESET>
|
||||
line 8<RESET>
|
||||
line 9<RESET>
|
||||
<CYAN>+<RESET><CYAN>line 1<RESET>
|
||||
<CYAN>+<RESET><CYAN>line 2<RESET>
|
||||
<CYAN>+<RESET><CYAN>line 3<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>line 14<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>line 15<RESET>
|
||||
<YELLOW>+<RESET><YELLOW>line 16<RESET>
|
||||
line 10<RESET>
|
||||
line 11<RESET>
|
||||
line 12<RESET>
|
||||
line 13<RESET>
|
||||
<MAGENTA>-line 14<RESET>
|
||||
<MAGENTA>-line 15<RESET>
|
||||
<MAGENTA>-line 16<RESET>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'no effect from --color-moved with --word-diff' '
|
||||
cat <<-\EOF >text.txt &&
|
||||
Lorem Ipsum is simply dummy text of the printing and typesetting industry.
|
||||
EOF
|
||||
git add text.txt &&
|
||||
git commit -a -m "clean state" &&
|
||||
cat <<-\EOF >text.txt &&
|
||||
simply Lorem Ipsum dummy is text of the typesetting and printing industry.
|
||||
EOF
|
||||
git diff --color-moved --word-diff >actual &&
|
||||
git diff --word-diff >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'move detection ignoring whitespace ' '
|
||||
git reset --hard &&
|
||||
cat <<\EOF >lines.txt &&
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
line 5
|
||||
line 6
|
||||
line 7
|
||||
EOF
|
||||
git add lines.txt &&
|
||||
git commit -m "add poetry" &&
|
||||
cat <<\EOF >lines.txt &&
|
||||
line 5
|
||||
line 6
|
||||
line 7
|
||||
line 1
|
||||
line 2
|
||||
line 3
|
||||
line 4
|
||||
EOF
|
||||
test_config color.diff.oldMoved "magenta" &&
|
||||
test_config color.diff.newMoved "cyan" &&
|
||||
git diff HEAD --no-renames --color-moved| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
|
||||
<BOLD>index 734156d..eb89ead 100644<RESET>
|
||||
<BOLD>--- a/lines.txt<RESET>
|
||||
<BOLD>+++ b/lines.txt<RESET>
|
||||
<CYAN>@@ -1,7 +1,7 @@<RESET>
|
||||
<GREEN>+<RESET> <GREEN>line 5<RESET>
|
||||
<GREEN>+<RESET> <GREEN>line 6<RESET>
|
||||
<GREEN>+<RESET> <GREEN>line 7<RESET>
|
||||
line 1<RESET>
|
||||
line 2<RESET>
|
||||
line 3<RESET>
|
||||
line 4<RESET>
|
||||
<RED>-line 5<RESET>
|
||||
<RED>-line 6<RESET>
|
||||
<RED>-line 7<RESET>
|
||||
EOF
|
||||
test_cmp expected actual &&
|
||||
|
||||
git diff HEAD --no-renames -w --color-moved| test_decode_color >actual &&
|
||||
cat <<-\EOF >expected &&
|
||||
<BOLD>diff --git a/lines.txt b/lines.txt<RESET>
|
||||
<BOLD>index 734156d..eb89ead 100644<RESET>
|
||||
<BOLD>--- a/lines.txt<RESET>
|
||||
<BOLD>+++ b/lines.txt<RESET>
|
||||
<CYAN>@@ -1,7 +1,7 @@<RESET>
|
||||
<CYAN>+<RESET> <CYAN>line 5<RESET>
|
||||
<CYAN>+<RESET> <CYAN>line 6<RESET>
|
||||
<CYAN>+<RESET> <CYAN>line 7<RESET>
|
||||
line 1<RESET>
|
||||
line 2<RESET>
|
||||
line 3<RESET>
|
||||
line 4<RESET>
|
||||
<MAGENTA>-line 5<RESET>
|
||||
<MAGENTA>-line 6<RESET>
|
||||
<MAGENTA>-line 7<RESET>
|
||||
EOF
|
||||
test_cmp expected actual
|
||||
'
|
||||
|
||||
test_expect_success 'move detection with submodules' '
|
||||
test_create_repo bananas &&
|
||||
echo ripe >bananas/recipe &&
|
||||
git -C bananas add recipe &&
|
||||
test_commit fruit &&
|
||||
test_commit -C bananas recipe &&
|
||||
git submodule add ./bananas &&
|
||||
git add bananas &&
|
||||
git commit -a -m "bananas are like a heavy library?" &&
|
||||
echo foul >bananas/recipe &&
|
||||
echo ripe >fruit.t &&
|
||||
|
||||
git diff --submodule=diff --color-moved >actual &&
|
||||
|
||||
# no move detection as the moved line is across repository boundaries.
|
||||
test_decode_color <actual >decoded_actual &&
|
||||
! grep BGREEN decoded_actual &&
|
||||
! grep BRED decoded_actual &&
|
||||
|
||||
# nor did we mess with it another way
|
||||
git diff --submodule=diff | test_decode_color >expect &&
|
||||
test_cmp expect decoded_actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in New Issue
Block a user