Add "git show-ref" builtin command
[gitweb.git] / builtin-apply.c
index 7dea913836d08ae3eb394b1fd73b9c92002f6cc7..6e0864ce27619d1153575876e2a617a392906aed 100644 (file)
@@ -28,7 +28,6 @@ static int prefix_length = -1;
 static int newfd = -1;
 
 static int p_value = 1;
-static int allow_binary_replacement;
 static int check_index;
 static int write_index;
 static int cached;
@@ -39,12 +38,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=<nowarn|warn|error|error-all|strip>] <patch>...";
+"git-apply [--stat] [--numstat] [--summary] [--check] [--index] [--cached] [--apply] [--no-add] [--index-info] [--allow-binary-replacement] [--reverse] [--reject] [--verbose] [-z] [-pNUM] [-CNUM] [--whitespace=<nowarn|warn|error|error-all|strip>] <patch>...";
 
 static enum whitespace_eol {
        nowarn_whitespace,
@@ -153,6 +153,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)
 
@@ -609,9 +627,7 @@ static char *git_header_name(char *line, int llen)
         * form.
         */
        for (len = 0 ; ; len++) {
-               char c = name[len];
-
-               switch (c) {
+               switch (name[len]) {
                default:
                        continue;
                case '\n':
@@ -1114,8 +1130,7 @@ static struct fragment *parse_binary_hunk(char **buf_p,
        return frag;
 
  corrupt:
-       if (data)
-               free(data);
+       free(data);
        *status_p = -1;
        error("corrupt binary patch at line %d: %.*s",
              linenr-1, llen-1, buffer);
@@ -1212,14 +1227,12 @@ static int parse_chunk(char *buffer, unsigned long size, struct patch *patch)
                        }
                }
 
-               /* Empty patch cannot be applied if:
-                * - it is a binary patch and we do not do binary_replace, or
-                * - text patch without metadata change
+               /* Empty patch cannot be applied if it is a text patch
+                * without metadata change.  A binary patch appears
+                * empty to us here.
                 */
                if ((apply || check) &&
-                   (patch->is_binary
-                    ? !allow_binary_replacement
-                    : !metadata_changes(patch)))
+                   (!patch->is_binary && !metadata_changes(patch)))
                        die("patch with only garbage at line %d", linenr);
        }
 
@@ -1312,8 +1325,7 @@ static void show_stats(struct patch *patch)
                printf(" %s%-*s |%5d %.*s%.*s\n", prefix,
                       len, name, patch->lines_added + patch->lines_deleted,
                       add, pluses, del, minuses);
-       if (qname)
-               free(qname);
+       free(qname);
 }
 
 static int read_old_data(struct stat *st, const char *path, void *buf, unsigned long size)
@@ -1661,11 +1673,6 @@ static int apply_binary(struct buffer_desc *desc, struct patch *patch)
        unsigned char hdr[50];
        int hdrlen;
 
-       if (!allow_binary_replacement)
-               return error("cannot apply binary patch to '%s' "
-                            "without --allow-binary-replacement",
-                            name);
-
        /* For safety, we require patch index line to contain
         * full 40-byte textual SHA1 for old and new, at least for now.
         */
@@ -1925,13 +1932,16 @@ static int check_patch(struct patch *patch, struct patch *prev_patch)
 static int check_patch_list(struct patch *patch)
 {
        struct patch *prev_patch = NULL;
-       int error = 0;
+       int err = 0;
 
        for (prev_patch = NULL; patch ; patch = patch->next) {
-               error |= check_patch(patch, prev_patch);
+               if (apply_verbosely)
+                       say_patch_name(stderr,
+                                      "Checking patch ", patch, "...\n");
+               err |= check_patch(patch, prev_patch);
                prev_patch = patch;
        }
-       return error;
+       return err;
 }
 
 static void show_index_list(struct patch *list)
@@ -2242,36 +2252,69 @@ 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) {
+               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.
+        */
+       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;
+               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 = 1, 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 +2331,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;
@@ -2405,7 +2441,7 @@ static int apply_patch(int fd, const char *filename, int inaccurate_eof)
 static int git_apply_config(const char *var, const char *value)
 {
        if (!strcmp(var, "apply.whitespace")) {
-               apply_default_whitespace = strdup(value);
+               apply_default_whitespace = xstrdup(value);
                return 0;
        }
        return git_default_config(var, value);
@@ -2453,8 +2489,7 @@ int cmd_apply(int argc, const char **argv, const char *prefix)
                }
                if (!strcmp(arg, "--allow-binary-replacement") ||
                    !strcmp(arg, "--binary")) {
-                       allow_binary_replacement = 1;
-                       continue;
+                       continue; /* now no-op */
                }
                if (!strcmp(arg, "--numstat")) {
                        apply = 0;
@@ -2509,7 +2544,11 @@ 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")) {
+                       apply_verbosely = 1;
                        continue;
                }
                if (!strcmp(arg, "--inaccurate-eof")) {