Merge branch 'js/apply-recount'

* js/apply-recount:
  Allow git-apply to recount the lines in a hunk (AKA recountdiff)
This commit is contained in:
Junio C Hamano 2008-07-01 16:22:39 -07:00
commit 27158e463a
3 changed files with 99 additions and 41 deletions

View File

@ -12,7 +12,7 @@ SYNOPSIS
'git-apply' [--stat] [--numstat] [--summary] [--check] [--index]
[--apply] [--no-add] [--build-fake-ancestor <file>] [-R | --reverse]
[--allow-binary-replacement | --binary] [--reject] [-z]
[-pNUM] [-CNUM] [--inaccurate-eof] [--cached]
[-pNUM] [-CNUM] [--inaccurate-eof] [--recount] [--cached]
[--whitespace=<nowarn|warn|fix|error|error-all>]
[--exclude=PATH] [--verbose] [<patch>...]
@ -177,6 +177,11 @@ behavior:
current patch being applied will be printed. This option will cause
additional information to be reported.
--recount::
Do not trust the line counts in the hunk headers, but infer them
by inspecting the patch (e.g. after editing the patch without
adjusting the hunk headers appropriately).
Configuration
-------------

View File

@ -154,6 +154,7 @@ struct patch {
unsigned int is_binary:1;
unsigned int is_copy:1;
unsigned int is_rename:1;
unsigned int recount:1;
struct fragment *fragments;
char *result;
size_t resultsize;
@ -890,6 +891,56 @@ static int parse_range(const char *line, int len, int offset, const char *expect
return offset + ex;
}
static void recount_diff(char *line, int size, struct fragment *fragment)
{
int oldlines = 0, newlines = 0, ret = 0;
if (size < 1) {
warning("recount: ignore empty hunk");
return;
}
for (;;) {
int len = linelen(line, size);
size -= len;
line += len;
if (size < 1)
break;
switch (*line) {
case ' ': case '\n':
newlines++;
/* fall through */
case '-':
oldlines++;
continue;
case '+':
newlines++;
continue;
case '\\':
break;
case '@':
ret = size < 3 || prefixcmp(line, "@@ ");
break;
case 'd':
ret = size < 5 || prefixcmp(line, "diff ");
break;
default:
ret = -1;
break;
}
if (ret) {
warning("recount: unexpected line: %.*s",
(int)linelen(line, size), line);
return;
}
break;
}
fragment->oldlines = oldlines;
fragment->newlines = newlines;
}
/*
* Parse a unified diff fragment header of the
* form "@@ -a,b +c,d @@"
@ -1020,6 +1071,8 @@ static int parse_fragment(char *line, unsigned long size,
offset = parse_fragment_header(line, len, fragment);
if (offset < 0)
return -1;
if (offset > 0 && patch->recount)
recount_diff(line + offset, size - offset, fragment);
oldlines = fragment->oldlines;
newlines = fragment->newlines;
leading = 0;
@ -2971,7 +3024,10 @@ static void prefix_patches(struct patch *p)
}
}
static int apply_patch(int fd, const char *filename, int inaccurate_eof)
#define INACCURATE_EOF (1<<0)
#define RECOUNT (1<<1)
static int apply_patch(int fd, const char *filename, int options)
{
size_t offset;
struct strbuf buf;
@ -2989,7 +3045,8 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
int nr;
patch = xcalloc(1, sizeof(*patch));
patch->inaccurate_eof = inaccurate_eof;
patch->inaccurate_eof = !!(options & INACCURATE_EOF);
patch->recount = !!(options & RECOUNT);
nr = parse_chunk(buf.buf + offset, buf.len - offset, patch);
if (nr < 0)
break;
@ -3058,7 +3115,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
{
int i;
int read_stdin = 1;
int inaccurate_eof = 0;
int options = 0;
int errs = 0;
int is_not_gitdir;
@ -3076,7 +3133,7 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
int fd;
if (!strcmp(arg, "-")) {
errs |= apply_patch(0, "<stdin>", inaccurate_eof);
errs |= apply_patch(0, "<stdin>", options);
read_stdin = 0;
continue;
}
@ -3176,7 +3233,11 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
continue;
}
if (!strcmp(arg, "--inaccurate-eof")) {
inaccurate_eof = 1;
options |= INACCURATE_EOF;
continue;
}
if (!strcmp(arg, "--recount")) {
options |= RECOUNT;
continue;
}
if (0 < prefix_length)
@ -3187,12 +3248,12 @@ int cmd_apply(int argc, const char **argv, const char *unused_prefix)
die("can't open patch '%s': %s", arg, strerror(errno));
read_stdin = 0;
set_default_whitespace_mode(whitespace_option);
errs |= apply_patch(fd, arg, inaccurate_eof);
errs |= apply_patch(fd, arg, options);
close(fd);
}
set_default_whitespace_mode(whitespace_option);
if (read_stdin)
errs |= apply_patch(0, "<stdin>", inaccurate_eof);
errs |= apply_patch(0, "<stdin>", options);
if (whitespace_error) {
if (squelch_whitespace_errors &&
squelch_whitespace_errors < whitespace_error) {

View File

@ -3,44 +3,36 @@
# Copyright (c) 2005 Junio C Hamano
#
test_description='git apply --stat --summary test.
test_description='git apply --stat --summary test, with --recount
'
. ./test-lib.sh
test_expect_success \
'rename' \
'git apply --stat --summary <../t4100/t-apply-1.patch >current &&
test_cmp ../t4100/t-apply-1.expect current'
UNC='s/^\(@@ -[1-9][0-9]*\),[0-9]* \(+[1-9][0-9]*\),[0-9]* @@/\1,999 \2,999 @@/'
test_expect_success \
'copy' \
'git apply --stat --summary <../t4100/t-apply-2.patch >current &&
test_cmp ../t4100/t-apply-2.expect current'
num=0
while read title
do
num=$(( $num + 1 ))
test_expect_success "$title" '
git apply --stat --summary \
<"$TEST_DIRECTORY/t4100/t-apply-$num.patch" >current &&
test_cmp ../t4100/t-apply-$num.expect current
'
test_expect_success \
'rewrite' \
'git apply --stat --summary <../t4100/t-apply-3.patch >current &&
test_cmp ../t4100/t-apply-3.expect current'
test_expect_success \
'mode' \
'git apply --stat --summary <../t4100/t-apply-4.patch >current &&
test_cmp ../t4100/t-apply-4.expect current'
test_expect_success \
'non git' \
'git apply --stat --summary <../t4100/t-apply-5.patch >current &&
test_cmp ../t4100/t-apply-5.expect current'
test_expect_success \
'non git' \
'git apply --stat --summary <../t4100/t-apply-6.patch >current &&
test_cmp ../t4100/t-apply-6.expect current'
test_expect_success \
'non git' \
'git apply --stat --summary <../t4100/t-apply-7.patch >current &&
test_cmp ../t4100/t-apply-7.expect current'
test_expect_success "$title with recount" '
sed -e "$UNC" <"$TEST_DIRECTORY/t4100/t-apply-$num.patch" |
git apply --recount --stat --summary >current &&
test_cmp ../t4100/t-apply-$num.expect current
'
done <<\EOF
rename
copy
rewrite
mode
non git (1)
non git (2)
non git (3)
EOF
test_done