Merge branch 'bc/unuse-packfile'
[gitweb.git] / builtin / apply.c
index 080ce2ea3e4d6290e5db5567c0bdd217725a36c4..50912c928f79cc0bcb4acf3ae50fd9fdc32193e8 100644 (file)
@@ -473,7 +473,7 @@ static char *find_name_gnu(const char *line, const char *def, int p_value)
 
        /*
         * Proposed "new-style" GNU patch/diff format; see
-        * http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2
+        * http://marc.info/?l=git&m=112927316408690&w=2
         */
        if (unquote_c_style(&name, line, NULL)) {
                strbuf_release(&name);
@@ -722,7 +722,7 @@ static char *find_name(const char *line, char *def, int p_value, int terminate)
 
 static char *find_name_traditional(const char *line, char *def, int p_value)
 {
-       size_t len = strlen(line);
+       size_t len;
        size_t date_len;
 
        if (*line == '"') {
@@ -906,7 +906,7 @@ static void parse_traditional_patch(const char *first, const char *second, struc
                        patch->old_name = name;
                } else {
                        patch->old_name = name;
-                       patch->new_name = xstrdup(name);
+                       patch->new_name = null_strdup(name);
                }
        }
        if (!name)
@@ -1921,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
@@ -2117,10 +2117,10 @@ static void update_pre_post_images(struct image *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.
         */
@@ -2185,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) {
@@ -2335,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;
@@ -2362,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)
@@ -2399,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:
@@ -2995,7 +2999,7 @@ static int read_blob_object(struct strbuf *buf, const unsigned char *sha1, unsig
        return 0;
 }
 
-static int read_file_or_gitlink(struct cache_entry *ce, struct strbuf *buf)
+static int read_file_or_gitlink(const struct cache_entry *ce, struct strbuf *buf)
 {
        if (!ce)
                return 0;
@@ -3025,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)
@@ -3113,7 +3117,7 @@ static struct patch *previous_patch(struct patch *patch, int *gone)
        return previous;
 }
 
-static int verify_index_match(struct cache_entry *ce, struct stat *st)
+static int verify_index_match(const struct cache_entry *ce, struct stat *st)
 {
        if (S_ISGITLINK(ce->ce_mode)) {
                if (!S_ISDIR(st->st_mode))
@@ -3126,7 +3130,7 @@ static int verify_index_match(struct cache_entry *ce, struct stat *st)
 #define SUBMODULE_PATCH_WITHOUT_INDEX 1
 
 static int load_patch_target(struct strbuf *buf,
-                            struct cache_entry *ce,
+                            const struct cache_entry *ce,
                             struct stat *st,
                             const char *name,
                             unsigned expected_mode)
@@ -3156,7 +3160,8 @@ static int load_patch_target(struct strbuf *buf,
  * we read from the result of a previous diff.
  */
 static int load_preimage(struct image *image,
-                        struct patch *patch, struct stat *st, struct cache_entry *ce)
+                        struct patch *patch, struct stat *st,
+                        const struct cache_entry *ce)
 {
        struct strbuf buf = STRBUF_INIT;
        size_t len;
@@ -3269,7 +3274,7 @@ static int load_current(struct image *image, struct patch *patch)
 }
 
 static int try_threeway(struct image *image, struct patch *patch,
-                       struct stat *st, struct cache_entry *ce)
+                       struct stat *st, const struct cache_entry *ce)
 {
        unsigned char pre_sha1[20], post_sha1[20], our_sha1[20];
        struct strbuf buf = STRBUF_INIT;
@@ -3339,7 +3344,7 @@ static int try_threeway(struct image *image, struct patch *patch,
        return 0;
 }
 
-static int apply_data(struct patch *patch, struct stat *st, struct cache_entry *ce)
+static int apply_data(struct patch *patch, struct stat *st, const struct cache_entry *ce)
 {
        struct image image;
 
@@ -3509,7 +3514,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().
@@ -3521,7 +3526,7 @@ static int check_patch(struct patch *patch)
                ok_if_exists = 0;
 
        if (new_name &&
-           ((0 < patch->is_new) | (0 < patch->is_rename) | patch->is_copy)) {
+           ((0 < patch->is_new) || patch->is_rename || patch->is_copy)) {
                int err = check_to_create(new_name, ok_if_exists);
 
                if (err && threeway) {
@@ -3600,6 +3605,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)
 {
@@ -3620,8 +3659,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 */
@@ -3807,7 +3848,7 @@ static void add_index_file(const char *path, unsigned mode, void *buf, unsigned
                const char *s = buf;
 
                if (get_sha1_hex(s + strlen("Subproject commit "), ce->sha1))
-                       die(_("corrupt patch for subproject %s"), path);
+                       die(_("corrupt patch for submodule %s"), path);
        } else {
                if (!cached) {
                        if (lstat(path, &st) < 0)