Merge branch 'jc/extended-fake-ancestor-for-gitlink'
authorJunio C Hamano <gitster@pobox.com>
Thu, 14 Feb 2013 18:28:48 +0000 (10:28 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 14 Feb 2013 18:28:48 +0000 (10:28 -0800)
Instead of requiring the full 40-hex object names on the index
line, we can read submodule commit object names from the textual
diff when synthesizing a fake ancestore tree for "git am -3".

* jc/extended-fake-ancestor-for-gitlink:
apply: verify submodule commit object name better

1  2 
builtin/apply.c
diff --combined builtin/apply.c
index 080ce2ea3e4d6290e5db5567c0bdd217725a36c4,445fea7af63c73d52facfaecc18f82d014d05217..06f5320b18bc5690ae944a722d19ec5496687228
@@@ -1041,17 -1041,15 +1041,17 @@@ static int gitdiff_renamedst(const cha
  
  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;
  }
  
@@@ -2097,7 -2095,7 +2097,7 @@@ static void update_pre_post_images(stru
                                   char *buf,
                                   size_t len, size_t postlen)
  {
 -      int i, ctx;
 +      int i, ctx, reduced;
        char *new, *old, *fixed;
        struct image fixed_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;
        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 */
                        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;
  
        /* Fix the length of the whole thing */
        postimage->len = new - postimage->buf;
 +      postimage->nr -= reduced;
  }
  
  static int match_fragment(struct image *img,
@@@ -3600,6 -3587,40 +3600,40 @@@ static int get_current_sha1(const char 
        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)
  {
                        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 */