exclude_existing(): set existing_refs.strdup_strings
[gitweb.git] / builtin / apply.c
index 1f78e2cfab73c6600ae9414b04bb44444e1d2a64..30eefc3c7b390800e9452a06da18208d2fef4f11 100644 (file)
@@ -1041,15 +1041,17 @@ static int gitdiff_renamedst(const char *line, struct patch *patch)
 
 static int gitdiff_similarity(const char *line, struct patch *patch)
 {
-       if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
-               patch->score = 0;
+       unsigned long val = strtoul(line, NULL, 10);
+       if (val <= 100)
+               patch->score = val;
        return 0;
 }
 
 static int gitdiff_dissimilarity(const char *line, struct patch *patch)
 {
-       if ((patch->score = strtoul(line, NULL, 10)) == ULONG_MAX)
-               patch->score = 0;
+       unsigned long val = strtoul(line, NULL, 10);
+       if (val <= 100)
+               patch->score = val;
        return 0;
 }
 
@@ -1919,7 +1921,7 @@ static int parse_binary(char *buffer, unsigned long size, struct patch *patch)
 }
 
 /*
- * Read the patch text in "buffer" taht extends for "size" bytes; stop
+ * Read the patch text in "buffer" that extends for "size" bytes; stop
  * reading after seeing a single patch (i.e. changes to a single file).
  * Create fragments (i.e. patch hunks) and hang them to the given patch.
  * Return the number of bytes consumed, so that the caller can call us
@@ -2095,7 +2097,7 @@ static void update_pre_post_images(struct image *preimage,
                                   char *buf,
                                   size_t len, size_t postlen)
 {
-       int i, ctx;
+       int i, ctx, reduced;
        char *new, *old, *fixed;
        struct image fixed_preimage;
 
@@ -2105,18 +2107,20 @@ static void update_pre_post_images(struct image *preimage,
         * free "oldlines".
         */
        prepare_image(&fixed_preimage, buf, len, 1);
-       assert(fixed_preimage.nr == preimage->nr);
-       for (i = 0; i < preimage->nr; i++)
+       assert(postlen
+              ? fixed_preimage.nr == preimage->nr
+              : fixed_preimage.nr <= preimage->nr);
+       for (i = 0; i < fixed_preimage.nr; i++)
                fixed_preimage.line[i].flag = preimage->line[i].flag;
        free(preimage->line_allocated);
        *preimage = fixed_preimage;
 
        /*
         * Adjust the common context lines in postimage. This can be
-        * done in-place when we are just doing whitespace fixing,
-        * which does not make the string grow, but needs a new buffer
-        * when ignoring whitespace causes the update, since in this case
-        * we could have e.g. tabs converted to multiple spaces.
+        * done in-place when we are shrinking it with whitespace
+        * fixing, but needs a new buffer when ignoring whitespace or
+        * expanding leading tabs to spaces.
+        *
         * We trust the caller to tell us if the update can be done
         * in place (postlen==0) or not.
         */
@@ -2126,7 +2130,8 @@ static void update_pre_post_images(struct image *preimage,
        else
                new = old;
        fixed = preimage->buf;
-       for (i = ctx = 0; i < postimage->nr; i++) {
+
+       for (i = reduced = ctx = 0; i < postimage->nr; i++) {
                size_t len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
@@ -2145,8 +2150,15 @@ static void update_pre_post_images(struct image *preimage,
                        fixed += preimage->line[ctx].len;
                        ctx++;
                }
-               if (preimage->nr <= ctx)
-                       die(_("oops"));
+
+               /*
+                * preimage is expected to run out, if the caller
+                * fixed addition of trailing blank lines.
+                */
+               if (preimage->nr <= ctx) {
+                       reduced++;
+                       continue;
+               }
 
                /* and copy it in, while fixing the line length */
                len = preimage->line[ctx].len;
@@ -2159,6 +2171,7 @@ static void update_pre_post_images(struct image *preimage,
 
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
+       postimage->nr -= reduced;
 }
 
 static int match_fragment(struct image *img,
@@ -2172,7 +2185,7 @@ static int match_fragment(struct image *img,
        int i;
        char *fixed_buf, *buf, *orig, *target;
        struct strbuf fixed;
-       size_t fixed_len;
+       size_t fixed_len, postlen;
        int preimage_limit;
 
        if (preimage->nr + try_lno <= img->nr) {
@@ -2322,6 +2335,7 @@ static int match_fragment(struct image *img,
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
        target = img->buf + try;
+       postlen = 0;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
                size_t tgtlen = img->line[try_lno + i].len;
@@ -2349,6 +2363,7 @@ static int match_fragment(struct image *img,
                match = (tgtfix.len == fixed.len - fixstart &&
                         !memcmp(tgtfix.buf, fixed.buf + fixstart,
                                             fixed.len - fixstart));
+               postlen += tgtfix.len;
 
                strbuf_release(&tgtfix);
                if (!match)
@@ -2386,8 +2401,10 @@ static int match_fragment(struct image *img,
         * hunk match.  Update the context lines in the postimage.
         */
        fixed_buf = strbuf_detach(&fixed, &fixed_len);
+       if (postlen < postimage->len)
+               postlen = 0;
        update_pre_post_images(preimage, postimage,
-                              fixed_buf, fixed_len, 0);
+                              fixed_buf, fixed_len, postlen);
        return 1;
 
  unmatch_exit:
@@ -3012,7 +3029,7 @@ static struct patch *in_fn_table(const char *name)
  *
  * The latter is needed to deal with a case where two paths A and B
  * are swapped by first renaming A to B and then renaming B to A;
- * moving A to B should not be prevented due to presense of B as we
+ * moving A to B should not be prevented due to presence of B as we
  * will remove it in a later patch.
  */
 #define PATH_TO_BE_DELETED ((struct patch *) -2)
@@ -3496,7 +3513,7 @@ static int check_patch(struct patch *patch)
         *
         * A patch to swap-rename between A and B would first rename A
         * to B and then rename B to A.  While applying the first one,
-        * the presense of B should not stop A from getting renamed to
+        * the presence of B should not stop A from getting renamed to
         * B; ask to_be_deleted() about the later rename.  Removal of
         * B and rename from A to B is handled the same way by asking
         * was_deleted().
@@ -3587,6 +3604,40 @@ static int get_current_sha1(const char *path, unsigned char *sha1)
        return 0;
 }
 
+static int preimage_sha1_in_gitlink_patch(struct patch *p, unsigned char sha1[20])
+{
+       /*
+        * A usable gitlink patch has only one fragment (hunk) that looks like:
+        * @@ -1 +1 @@
+        * -Subproject commit <old sha1>
+        * +Subproject commit <new sha1>
+        * or
+        * @@ -1 +0,0 @@
+        * -Subproject commit <old sha1>
+        * for a removal patch.
+        */
+       struct fragment *hunk = p->fragments;
+       static const char heading[] = "-Subproject commit ";
+       char *preimage;
+
+       if (/* does the patch have only one hunk? */
+           hunk && !hunk->next &&
+           /* is its preimage one line? */
+           hunk->oldpos == 1 && hunk->oldlines == 1 &&
+           /* does preimage begin with the heading? */
+           (preimage = memchr(hunk->patch, '\n', hunk->size)) != NULL &&
+           !prefixcmp(++preimage, heading) &&
+           /* does it record full SHA-1? */
+           !get_sha1_hex(preimage + sizeof(heading) - 1, sha1) &&
+           preimage[sizeof(heading) + 40 - 1] == '\n' &&
+           /* does the abbreviated name on the index line agree with it? */
+           !prefixcmp(preimage + sizeof(heading) - 1, p->old_sha1_prefix))
+               return 0; /* it all looks fine */
+
+       /* we may have full object name on the index line */
+       return get_sha1_hex(p->old_sha1_prefix, sha1);
+}
+
 /* Build an index that contains the just the files needed for a 3way merge */
 static void build_fake_ancestor(struct patch *list, const char *filename)
 {
@@ -3607,8 +3658,10 @@ static void build_fake_ancestor(struct patch *list, const char *filename)
                        continue;
 
                if (S_ISGITLINK(patch->old_mode)) {
-                       if (get_sha1_hex(patch->old_sha1_prefix, sha1))
-                               die("submoule change for %s without full index name",
+                       if (!preimage_sha1_in_gitlink_patch(patch, sha1))
+                               ; /* ok, the textual part looks sane */
+                       else
+                               die("sha1 information is lacking or useless for submoule %s",
                                    name);
                } else if (!get_sha1_blob(patch->old_sha1_prefix, sha1)) {
                        ; /* ok */