From 03eb8f8aeb8a483b11b797cca012fdded818a5c1 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 16 Aug 2006 16:07:20 -0700 Subject: builtin-apply --reverse: two bugfixes. Parsing of a binary hunk did not consume the terminating blank line. When applying in reverse, it did not use the second, reverse binary hunk. Signed-off-by: Junio C Hamano diff --git a/builtin-apply.c b/builtin-apply.c index 4f0eef0..be6e94d 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -1063,8 +1063,12 @@ static struct fragment *parse_binary_hunk(char **buf_p, llen = linelen(buffer, size); used += llen; linenr++; - if (llen == 1) + if (llen == 1) { + /* consume the blank line */ + buffer++; + size--; break; + } /* Minimum line is "A00000\n" which is 7-byte long, * and the line length must be multiple of 5 plus 2. */ @@ -1618,7 +1622,7 @@ static int apply_binary_fragment(struct buffer_desc *desc, struct patch *patch) "without the reverse hunk to '%s'", patch->new_name ? patch->new_name : patch->old_name); - fragment = fragment; + fragment = fragment->next; } data = (void*) fragment->patch; switch (fragment->binary_patch_method) { @@ -1717,7 +1721,7 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch) write_sha1_file_prepare(desc->buffer, desc->size, blob_type, sha1, hdr, &hdrlen); if (strcmp(sha1_to_hex(sha1), patch->new_sha1_prefix)) - return error("binary patch to '%s' creates incorrect result", name); + return error("binary patch to '%s' creates incorrect result (expecting %s, got %s)", name, patch->new_sha1_prefix, sha1_to_hex(sha1)); } return 0; -- cgit v0.10.2-6-g49f6 From d4c452f03b49072ebb46fc524e6d85056a35ef13 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 16 Aug 2006 16:08:14 -0700 Subject: diff.c: make binary patch reversible. This matches the format previous "git-apply --reverse" update expects. Signed-off-by: Junio C Hamano diff --git a/diff.c b/diff.c index 7a238d0..b816196 100644 --- a/diff.c +++ b/diff.c @@ -838,7 +838,7 @@ static unsigned char *deflate_it(char *data, return deflated; } -static void emit_binary_diff(mmfile_t *one, mmfile_t *two) +static void emit_binary_diff_body(mmfile_t *one, mmfile_t *two) { void *cp; void *delta; @@ -849,7 +849,6 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two) unsigned long deflate_size; unsigned long data_size; - printf("GIT binary patch\n"); /* We could do deflated delta, or we could do just deflated two, * whichever is smaller. */ @@ -898,6 +897,13 @@ static void emit_binary_diff(mmfile_t *one, mmfile_t *two) free(data); } +static void emit_binary_diff(mmfile_t *one, mmfile_t *two) +{ + printf("GIT binary patch\n"); + emit_binary_diff_body(one, two); + emit_binary_diff_body(two, one); +} + #define FIRST_FEW_BYTES 8000 static int mmfile_is_binary(mmfile_t *mf) { -- cgit v0.10.2-6-g49f6 From 2cda1a214e9d2e362242027b4b622ecb3d9260de Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 16 Aug 2006 16:09:25 -0700 Subject: apply --reverse: tie it all together. Add a few tests, usage string, and documentation. Signed-off-by: Junio C Hamano diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index 2ff7494..f1ab1f9 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -10,7 +10,8 @@ SYNOPSIS -------- [verse] 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] - [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] + [--no-add] [--index-info] [--allow-binary-replacement] + [--reverse] [-z] [-pNUM] [-CNUM] [--whitespace=] [...] @@ -62,6 +63,9 @@ OPTIONS the original version of the blob is available locally, outputs information about them to the standard output. +--reverse:: + Apply the patch in reverse. + -z:: When showing the index information, do not munge paths, but use NUL terminated machine readable format. Without diff --git a/builtin-apply.c b/builtin-apply.c index be6e94d..4737b64 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -43,7 +43,7 @@ static int show_index_info; static int line_termination = '\n'; static unsigned long p_context = -1; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; +"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; static enum whitespace_eol { nowarn_whitespace, diff --git a/t/t4116-apply-reverse.sh b/t/t4116-apply-reverse.sh index 69aebe6..74f5c2a 100755 --- a/t/t4116-apply-reverse.sh +++ b/t/t4116-apply-reverse.sh @@ -22,25 +22,64 @@ test_expect_success setup ' tr "[mon]" '\''[\0\1\2]'\'' file2 && git commit -a -m second && + git tag second && - git diff --binary -R initial >patch + git diff --binary initial second >patch ' test_expect_success 'apply in forward' ' + T0=`git rev-parse "second^{tree}"` && + git reset --hard initial && git apply --index --binary patch && - git diff initial >diff && - diff -u /dev/null diff - + T1=`git write-tree` && + test "$T0" = "$T1" ' test_expect_success 'apply in reverse' ' + git reset --hard second && git apply --reverse --binary --index patch && git diff >diff && diff -u /dev/null diff ' +test_expect_success 'setup separate repository lacking postimage' ' + + git tar-tree initial initial | tar xf - && + ( + cd initial && git init-db && git add . + ) && + + git tar-tree second second | tar xf - && + ( + cd second && git init-db && git add . + ) + +' + +test_expect_success 'apply in forward without postimage' ' + + T0=`git rev-parse "second^{tree}"` && + ( + cd initial && + git apply --index --binary ../patch && + T1=`git write-tree` && + test "$T0" = "$T1" + ) +' + +test_expect_success 'apply in reverse without postimage' ' + + T0=`git rev-parse "initial^{tree}"` && + ( + cd second && + git apply --index --binary --reverse ../patch && + T1=`git write-tree` && + test "$T0" = "$T1" + ) +' + test_done -- cgit v0.10.2-6-g49f6 From 57dc397cff09bfabd79ddbc38b704cdd0c2bc6e3 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 16 Aug 2006 17:55:29 -0700 Subject: git-apply --reject With the new flag "--reject", hunks that do not apply are sent to the standard output, and the usable hunks are applied. The command itself exits with non-zero status when this happens, so that the user or wrapper can take notice and sort the remaining mess out. Signed-off-by: Junio C Hamano diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index f1ab1f9..11641a9 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -11,7 +11,7 @@ SYNOPSIS [verse] 'git-apply' [--stat] [--numstat] [--summary] [--check] [--index] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] - [--reverse] [-z] [-pNUM] + [--reverse] [--reject] [-z] [-pNUM] [-CNUM] [--whitespace=] [...] @@ -66,6 +66,13 @@ OPTIONS --reverse:: Apply the patch in reverse. +--reject:: + For atomicity, `git apply` fails the whole patch and + does not touch the working tree when some of the hunks + do not apply by default. This option makes it apply + parts of the patch that are applicable, and send the + rejected hunks to the standard output of the command. + -z:: When showing the index information, do not munge paths, but use NUL terminated machine readable format. Without diff --git a/builtin-apply.c b/builtin-apply.c index 4737b64..7dea913 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -38,12 +38,13 @@ static int summary; static int check; static int apply = 1; static int apply_in_reverse; +static int apply_with_reject; static int no_add; static int show_index_info; static int line_termination = '\n'; static unsigned long p_context = -1; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; +"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; static enum whitespace_eol { nowarn_whitespace, @@ -122,6 +123,7 @@ struct fragment { unsigned long newpos, newlines; const char *patch; int size; + int rejected; struct fragment *next; }; @@ -138,6 +140,7 @@ struct patch { char *new_name, *old_name, *def_name; unsigned int old_mode, new_mode; int is_rename, is_copy, is_new, is_delete, is_binary; + int rejected; unsigned long deflate_origlen; int lines_added, lines_deleted; int score; @@ -1548,7 +1551,8 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i lines = 0; pos = frag->newpos; for (;;) { - offset = find_offset(buf, desc->size, oldlines, oldsize, pos, &lines); + offset = find_offset(buf, desc->size, + oldlines, oldsize, pos, &lines); if (match_end && offset + oldsize != desc->size) offset = -1; if (match_beginning && offset) @@ -1561,8 +1565,10 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i /* Warn if it was necessary to reduce the number * of context lines. */ - if ((leading != frag->leading) || (trailing != frag->trailing)) - fprintf(stderr, "Context reduced to (%ld/%ld) to apply fragment at %d\n", + if ((leading != frag->leading) || + (trailing != frag->trailing)) + fprintf(stderr, "Context reduced to (%ld/%ld)" + " to apply fragment at %d\n", leading, trailing, pos + lines); if (size > alloc) { @@ -1572,7 +1578,9 @@ static int apply_one_fragment(struct buffer_desc *desc, struct fragment *frag, i desc->buffer = buf; } desc->size = size; - memmove(buf + offset + newsize, buf + offset + oldsize, size - offset - newsize); + memmove(buf + offset + newsize, + buf + offset + oldsize, + size - offset - newsize); memcpy(buf + offset, newlines, newsize); offset = 0; @@ -1736,9 +1744,12 @@ static int apply_fragments(struct buffer_desc *desc, struct patch *patch) return apply_binary(desc, patch); while (frag) { - if (apply_one_fragment(desc, frag, patch->inaccurate_eof) < 0) - return error("patch failed: %s:%ld", - name, frag->oldpos); + if (apply_one_fragment(desc, frag, patch->inaccurate_eof)) { + error("patch failed: %s:%ld", name, frag->oldpos); + if (!apply_with_reject) + return -1; + frag->rejected = 1; + } frag = frag->next; } return 0; @@ -1774,8 +1785,9 @@ static int apply_data(struct patch *patch, struct stat *st, struct cache_entry * desc.size = size; desc.alloc = alloc; desc.buffer = buf; + if (apply_fragments(&desc, patch) < 0) - return -1; + return -1; /* note with --reject this succeeds. */ /* NUL terminate the result */ if (desc.alloc <= desc.size) @@ -1800,6 +1812,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) struct cache_entry *ce = NULL; int ok_if_exists; + patch->rejected = 1; /* we will drop this after we succeed */ if (old_name) { int changed = 0; int stat_ret = 0; @@ -1905,6 +1918,7 @@ static int check_patch(struct patch *patch, struct patch *prev_patch) if (apply_data(patch, &st, ce) < 0) return error("%s: patch does not apply", name); + patch->rejected = 0; return 0; } @@ -2223,23 +2237,73 @@ static void write_out_one_result(struct patch *patch, int phase) if (phase == 0) remove_file(patch); if (phase == 1) - create_file(patch); + create_file(patch); } -static void write_out_results(struct patch *list, int skipped_patch) +static int write_out_one_reject(struct patch *patch) +{ + struct fragment *frag; + int rejects = 0; + + for (rejects = 0, frag = patch->fragments; frag; frag = frag->next) { + if (!frag->rejected) + continue; + if (rejects == 0) { + rejects = 1; + printf("** Rejected hunk(s) for "); + if (patch->old_name && patch->new_name && + strcmp(patch->old_name, patch->new_name)) { + write_name_quoted(NULL, 0, + patch->old_name, 1, stdout); + fputs(" => ", stdout); + write_name_quoted(NULL, 0, + patch->new_name, 1, stdout); + } + else { + const char *n = patch->new_name; + if (!n) + n = patch->old_name; + write_name_quoted(NULL, 0, n, 1, stdout); + } + printf(" **\n"); + } + printf("%.*s", frag->size, frag->patch); + if (frag->patch[frag->size-1] != '\n') + putchar('\n'); + } + return rejects; +} + +static int write_out_results(struct patch *list, int skipped_patch) { int phase; + int errs = 0; + struct patch *l; if (!list && !skipped_patch) - die("No changes"); + return error("No changes"); for (phase = 0; phase < 2; phase++) { - struct patch *l = list; + l = list; + while (l) { + if (l->rejected) + errs = 1; + else + write_out_one_result(l, phase); + l = l->next; + } + } + if (apply_with_reject) { + l = list; while (l) { - write_out_one_result(l, phase); + if (!l->rejected) { + if (write_out_one_reject(l)) + errs = 1; + } l = l->next; } } + return errs; } static struct lock_file lock_file; @@ -2314,11 +2378,13 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof) die("unable to read index file"); } - if ((check || apply) && check_patch_list(list) < 0) + if ((check || apply) && + check_patch_list(list) < 0 && + !apply_with_reject) exit(1); - if (apply) - write_out_results(list, skipped_patch); + if (apply && write_out_results(list, skipped_patch)) + exit(1); if (show_index_info) show_index_list(list); @@ -2351,6 +2417,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix) int i; int read_stdin = 1; int inaccurate_eof = 0; + int errs = 0; const char *whitespace_option = NULL; @@ -2360,7 +2427,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix) int fd; if (!strcmp(arg, "-")) { - apply_patch(0, "", inaccurate_eof); + errs |= apply_patch(0, "", inaccurate_eof); read_stdin = 0; continue; } @@ -2441,6 +2508,10 @@ int cmd_apply(int argc, const char **argv, const char *prefix) apply_in_reverse = 1; continue; } + if (!strcmp(arg, "--reject")) { + apply = apply_with_reject = 1; + continue; + } if (!strcmp(arg, "--inaccurate-eof")) { inaccurate_eof = 1; continue; @@ -2461,18 +2532,19 @@ int cmd_apply(int argc, const char **argv, const char *prefix) usage(apply_usage); read_stdin = 0; set_default_whitespace_mode(whitespace_option); - apply_patch(fd, arg, inaccurate_eof); + errs |= apply_patch(fd, arg, inaccurate_eof); close(fd); } set_default_whitespace_mode(whitespace_option); if (read_stdin) - apply_patch(0, "", inaccurate_eof); + errs |= apply_patch(0, "", inaccurate_eof); if (whitespace_error) { if (squelch_whitespace_errors && squelch_whitespace_errors < whitespace_error) { int squelched = whitespace_error - squelch_whitespace_errors; - fprintf(stderr, "warning: squelched %d whitespace error%s\n", + fprintf(stderr, "warning: squelched %d " + "whitespace error%s\n", squelched, squelched == 1 ? "" : "s"); } @@ -2500,5 +2572,5 @@ int cmd_apply(int argc, const char **argv, const char *prefix) die("Unable to write new index file"); } - return 0; + return !!errs; } diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh new file mode 100755 index 0000000..3362819 --- /dev/null +++ b/t/t4117-apply-reject.sh @@ -0,0 +1,96 @@ +#!/bin/sh +# +# Copyright (c) 2005 Junio C Hamano +# + +test_description='git-apply with rejects + +' + +. ./test-lib.sh + +test_expect_success setup ' + for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 + do + echo $i + done >file1 && + cat file1 >saved.file1 && + git update-index --add file1 && + git commit -m initial && + + for i in 1 2 A B 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 D 21 + do + echo $i + done >file1 && + git diff >patch.1 && + + mv file1 file2 && + git update-index --add --remove file1 file2 && + git diff -M HEAD >patch.2 && + + rm -f file1 file2 && + mv saved.file1 file1 && + git update-index --add --remove file1 file2 && + + for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 F 21 + do + echo $i + done >file1 && + + cat file1 >saved.file1 +' + +test_expect_success 'apply without --reject should fail' ' + + if git apply patch.1 + then + echo "Eh? Why?" + exit 1 + fi + + diff -u file1 saved.file1 +' + +test_expect_success 'apply with --reject should fail but update the file' ' + + cat saved.file1 >file1 + + if git apply --reject patch.1 >rejects + then + echo "succeeds with --reject?" + exit 1 + fi + cat rejects + for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 + do + echo $i + done >expected.file1 && + + diff -u file1 expected.file1 +' + +test_expect_success 'apply with --reject should fail but update the file' ' + + cat saved.file1 >file1 + + if git apply --reject patch.2 >rejects + then + echo "succeeds with --reject?" + exit 1 + fi + + cat rejects + + for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 + do + echo $i + done >expected.file2 && + + test -f file1 && { + echo "file1 still exists?" + exit 1 + } + diff -u file2 expected.file2 +' + +test_done -- cgit v0.10.2-6-g49f6 From 82e2765f59126f96da6e5dc30adf7c6189e9697d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Aug 2006 03:10:19 -0700 Subject: git-apply --reject: send rejects to .rej files. ... just like everybody else does, instead of sending it to the standard output, which was just silly. Signed-off-by: Junio C Hamano diff --git a/builtin-apply.c b/builtin-apply.c index 7dea913..668be9c 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2242,36 +2242,61 @@ static void write_out_one_result(struct patch *patch, int phase) static int write_out_one_reject(struct patch *patch) { + FILE *rej; + char namebuf[PATH_MAX]; struct fragment *frag; - int rejects = 0; + int cnt = 0; - for (rejects = 0, frag = patch->fragments; frag; frag = frag->next) { + for (cnt = 0, frag = patch->fragments; frag; frag = frag->next) { if (!frag->rejected) continue; - if (rejects == 0) { - rejects = 1; - printf("** Rejected hunk(s) for "); - if (patch->old_name && patch->new_name && - strcmp(patch->old_name, patch->new_name)) { - write_name_quoted(NULL, 0, - patch->old_name, 1, stdout); - fputs(" => ", stdout); - write_name_quoted(NULL, 0, - patch->new_name, 1, stdout); - } - else { - const char *n = patch->new_name; - if (!n) - n = patch->old_name; - write_name_quoted(NULL, 0, n, 1, stdout); - } - printf(" **\n"); + cnt++; + } + + if (!cnt) + return 0; + + /* This should not happen, because a removal patch that leaves + * contents are marked "rejected" at the patch level. + */ + if (!patch->new_name) + die("internal error"); + + cnt = strlen(patch->new_name); + if (ARRAY_SIZE(namebuf) <= cnt + 5) { + cnt = ARRAY_SIZE(namebuf) - 5; + fprintf(stderr, + "warning: truncating .rej filename to %.*s.rej", + cnt - 1, patch->new_name); + } + memcpy(namebuf, patch->new_name, cnt); + memcpy(namebuf + cnt, ".rej", 5); + + rej = fopen(namebuf, "w"); + if (!rej) + return error("cannot open %s: %s", namebuf, strerror(errno)); + + /* Normal git tools never deal with .rej, so do not pretend + * this is a git patch by saying --git nor give extended + * headers. While at it, maybe please "kompare" that wants + * the trailing TAB and some garbage at the end of line ;-). + */ + fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n", + patch->new_name, patch->new_name); + for (cnt = 0, frag = patch->fragments; + frag; + cnt++, frag = frag->next) { + if (!frag->rejected) { + fprintf(stderr, "Hunk #%d applied cleanly.\n", cnt); + continue; } - printf("%.*s", frag->size, frag->patch); + fprintf(stderr, "Rejected hunk #%d.\n", cnt); + fprintf(rej, "%.*s", frag->size, frag->patch); if (frag->patch[frag->size-1] != '\n') - putchar('\n'); + fputc('\n', rej); } - return rejects; + fclose(rej); + return -1; } static int write_out_results(struct patch *list, int skipped_patch) @@ -2288,16 +2313,9 @@ static int write_out_results(struct patch *list, int skipped_patch) while (l) { if (l->rejected) errs = 1; - else + else { write_out_one_result(l, phase); - l = l->next; - } - } - if (apply_with_reject) { - l = list; - while (l) { - if (!l->rejected) { - if (write_out_one_reject(l)) + if (phase == 1 && write_out_one_reject(l)) errs = 1; } l = l->next; diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index 3362819..1cf9a2e 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -23,6 +23,12 @@ test_expect_success setup ' echo $i done >file1 && git diff >patch.1 && + cat file1 >clean && + + for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 + do + echo $i + done >expected && mv file1 file2 && git update-index --add --remove file1 file2 && @@ -53,25 +59,30 @@ test_expect_success 'apply without --reject should fail' ' test_expect_success 'apply with --reject should fail but update the file' ' - cat saved.file1 >file1 + cat saved.file1 >file1 && + rm -f file1.rej file2.rej && - if git apply --reject patch.1 >rejects + if git apply --reject patch.1 then echo "succeeds with --reject?" exit 1 fi - cat rejects - for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 - do - echo $i - done >expected.file1 && - diff -u file1 expected.file1 + diff -u file1 expected && + + cat file1.rej && + + if test -f file2.rej + then + echo "file2 should not have been touched" + exit 1 + fi ' test_expect_success 'apply with --reject should fail but update the file' ' - cat saved.file1 >file1 + cat saved.file1 >file1 && + rm -f file1.rej file2.rej file2 && if git apply --reject patch.2 >rejects then @@ -79,18 +90,20 @@ test_expect_success 'apply with --reject should fail but update the file' ' exit 1 fi - cat rejects - - for i in 1 E 2 3 4 5 6 7 8 9 10 11 12 C 13 14 15 16 17 18 19 20 F 21 - do - echo $i - done >expected.file2 && - test -f file1 && { echo "file1 still exists?" exit 1 } - diff -u file2 expected.file2 + diff -u file2 expected && + + cat file2.rej && + + if test -f file1.rej + then + echo "file2 should not have been touched" + exit 1 + fi + ' test_done -- cgit v0.10.2-6-g49f6 From a2bf404e280b8d56d0efa15bd9700464cf8f0d4d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 18 Aug 2006 03:14:48 -0700 Subject: git-apply --verbose Signed-off-by: Junio C Hamano diff --git a/builtin-apply.c b/builtin-apply.c index 668be9c..42253e6 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -39,12 +39,13 @@ static int check; static int apply = 1; static int apply_in_reverse; static int apply_with_reject; +static int apply_verbosely; static int no_add; static int show_index_info; static int line_termination = '\n'; static unsigned long p_context = -1; static const char apply_usage[] = -"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; +"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=] ..."; static enum whitespace_eol { nowarn_whitespace, @@ -153,6 +154,24 @@ struct patch { struct patch *next; }; +static void say_patch_name(FILE *output, const char *pre, struct patch *patch, const char *post) +{ + fputs(pre, output); + if (patch->old_name && patch->new_name && + strcmp(patch->old_name, patch->new_name)) { + write_name_quoted(NULL, 0, patch->old_name, 1, output); + fputs(" => ", output); + write_name_quoted(NULL, 0, patch->new_name, 1, output); + } + else { + const char *n = patch->new_name; + if (!n) + n = patch->old_name; + write_name_quoted(NULL, 0, n, 1, output); + } + fputs(post, output); +} + #define CHUNKSIZE (8192) #define SLOP (16) @@ -1928,6 +1947,9 @@ static int check_patch_list(struct patch *patch) int error = 0; for (prev_patch = NULL; patch ; patch = patch->next) { + if (apply_verbosely) + say_patch_name(stderr, + "Checking patch ", patch, "...\n"); error |= check_patch(patch, prev_patch); prev_patch = patch; } @@ -2253,8 +2275,12 @@ static int write_out_one_reject(struct patch *patch) cnt++; } - if (!cnt) + if (!cnt) { + if (apply_verbosely) + say_patch_name(stderr, + "Applied patch ", patch, " cleanly.\n"); return 0; + } /* This should not happen, because a removal patch that leaves * contents are marked "rejected" at the patch level. @@ -2262,6 +2288,10 @@ static int write_out_one_reject(struct patch *patch) if (!patch->new_name) die("internal error"); + /* Say this even without --verbose */ + say_patch_name(stderr, "Applying patch ", patch, " with"); + fprintf(stderr, " %d rejects...\n", cnt); + cnt = strlen(patch->new_name); if (ARRAY_SIZE(namebuf) <= cnt + 5) { cnt = ARRAY_SIZE(namebuf) - 5; @@ -2530,6 +2560,10 @@ int cmd_apply(int argc, const char **argv, const char *prefix) apply = apply_with_reject = 1; continue; } + if (!strcmp(arg, "--verbose")) { + apply_verbosely = 1; + continue; + } if (!strcmp(arg, "--inaccurate-eof")) { inaccurate_eof = 1; continue; diff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh index 1cf9a2e..b4de075 100755 --- a/t/t4117-apply-reject.sh +++ b/t/t4117-apply-reject.sh @@ -57,6 +57,17 @@ test_expect_success 'apply without --reject should fail' ' diff -u file1 saved.file1 ' +test_expect_success 'apply without --reject should fail' ' + + if git apply --verbose patch.1 + then + echo "Eh? Why?" + exit 1 + fi + + diff -u file1 saved.file1 +' + test_expect_success 'apply with --reject should fail but update the file' ' cat saved.file1 >file1 && @@ -106,4 +117,41 @@ test_expect_success 'apply with --reject should fail but update the file' ' ' +test_expect_success 'the same test with --verbose' ' + + cat saved.file1 >file1 && + rm -f file1.rej file2.rej file2 && + + if git apply --reject --verbose patch.2 >rejects + then + echo "succeeds with --reject?" + exit 1 + fi + + test -f file1 && { + echo "file1 still exists?" + exit 1 + } + diff -u file2 expected && + + cat file2.rej && + + if test -f file1.rej + then + echo "file2 should not have been touched" + exit 1 + fi + +' + +test_expect_success 'apply cleanly with --verbose' ' + + git cat-file -p HEAD:file1 >file1 && + rm -f file?.rej file2 && + + git apply --verbose patch.1 && + + diff -u file1 clean +' + test_done -- cgit v0.10.2-6-g49f6 From 0e9ee32358413feaa4e1cb664cb0a1e6d52f434f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 22 Aug 2006 15:49:28 -0700 Subject: apply --reject: count hunks starting from 1, not 0 Signed-off-by: Junio C Hamano diff --git a/builtin-apply.c b/builtin-apply.c index 42253e6..a874375 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2313,7 +2313,7 @@ static int write_out_one_reject(struct patch *patch) */ fprintf(rej, "diff a/%s b/%s\t(rejected hunks)\n", patch->new_name, patch->new_name); - for (cnt = 0, frag = patch->fragments; + for (cnt = 1, frag = patch->fragments; frag; cnt++, frag = frag->next) { if (!frag->rejected) { -- cgit v0.10.2-6-g49f6 From 8938045a4eae7a9c39631508a3c3d34c50c6257a Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 27 Aug 2006 15:53:20 -0700 Subject: git-apply --reject: finishing touches. After a failed "git am" attempt: git apply --reject --verbose .dotest/patch applies hunks that are applicable and leaves *.rej files the rejected hunks, and it reports what it is doing. With --index, files with a rejected hunk do not get their index entries updated at all, so "git diff" will show the hunks that successfully got applied. Without --verbose to remind the user that the patch updated some other paths cleanly, it is very easy to lose track of the status of the working tree, so --reject implies --verbose. Signed-off-by: Junio C Hamano diff --git a/Documentation/git-apply.txt b/Documentation/git-apply.txt index 11641a9..2e2acd7 100644 --- a/Documentation/git-apply.txt +++ b/Documentation/git-apply.txt @@ -70,8 +70,8 @@ OPTIONS For atomicity, `git apply` fails the whole patch and does not touch the working tree when some of the hunks do not apply by default. This option makes it apply - parts of the patch that are applicable, and send the - rejected hunks to the standard output of the command. + parts of the patch that are applicable, and leave the + rejected hunks in corresponding *.rej files. -z:: When showing the index information, do not munge paths, diff --git a/builtin-apply.c b/builtin-apply.c index a874375..0b00a98 100644 --- a/builtin-apply.c +++ b/builtin-apply.c @@ -2557,7 +2557,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix) continue; } if (!strcmp(arg, "--reject")) { - apply = apply_with_reject = 1; + apply = apply_with_reject = apply_verbosely = 1; continue; } if (!strcmp(arg, "--verbose")) { -- cgit v0.10.2-6-g49f6