Merge branch 'jk/diff-blob'
authorJunio C Hamano <gitster@pobox.com>
Fri, 2 Jun 2017 06:06:05 +0000 (15:06 +0900)
committerJunio C Hamano <gitster@pobox.com>
Fri, 2 Jun 2017 06:06:05 +0000 (15:06 +0900)
The result from "git diff" that compares two blobs, e.g. "git diff
$commit1:$path $commit2:$path", used to be shown with the full
object name as given on the command line, but it is more natural to
use the $path in the output and use it to look up .gitattributes.

* jk/diff-blob:
diff: use blob path for blob/file diffs
diff: use pending "path" if it is available
diff: use the word "path" instead of "name" for blobs
diff: pass whole pending entry in blobinfo
handle_revision_arg: record paths for pending objects
handle_revision_arg: record modes for "a..b" endpoints
t4063: add tests of direct blob diffs
get_sha1_with_context: dynamically allocate oc->path
get_sha1_with_context: always initialize oc->symlink_path
sha1_name: consistently refer to object_context as "oc"
handle_revision_arg: add handle_dotdot() helper
handle_revision_arg: hoist ".." check out of range parsing
handle_revision_arg: stop using "dotdot" as a generic pointer
handle_revision_arg: simplify commit reference lookups
handle_revision_arg: reset "dotdot" consistently

1  2 
builtin/cat-file.c
builtin/diff.c
builtin/grep.c
builtin/log.c
cache.h
revision.c
sha1_name.c
t/t4202-log.sh
tree-walk.c
index 9af863e7915d21aee7af3cb4d01ebbad2efbcb59,421709517c765d83fa4a4abf00ff3b8a9dd79f64..73c81f0cb1ae34169667adc7ee7fc246468e08a4
@@@ -165,7 -166,7 +166,8 @@@ static int cat_one_file(int opt, const 
                die("git cat-file %s: bad file", obj_name);
  
        write_or_die(1, buf, size);
 +      free(buf);
+       free(obj_context.path);
        return 0;
  }
  
diff --cc builtin/diff.c
Simple merge
diff --cc builtin/grep.c
Simple merge
diff --cc builtin/log.c
Simple merge
diff --cc cache.h
Simple merge
diff --cc revision.c
index b02394530926ebe24233de5e6653e7127755675a,a927d263a53f62cc7bcb0b9db0f25f250b759bc6..3680a43a6e35d9850414b42f663acdc184d4d366
@@@ -1429,12 -1429,123 +1429,123 @@@ static void prepare_show_merge(struct r
        revs->limited = 1;
  }
  
 -      a_obj = parse_object(a_oid.hash);
 -      b_obj = parse_object(b_oid.hash);
+ static int dotdot_missing(const char *arg, char *dotdot,
+                         struct rev_info *revs, int symmetric)
+ {
+       if (revs->ignore_missing)
+               return 0;
+       /* de-munge so we report the full argument */
+       *dotdot = '.';
+       die(symmetric
+           ? "Invalid symmetric difference expression %s"
+           : "Invalid revision range %s", arg);
+ }
+ static int handle_dotdot_1(const char *arg, char *dotdot,
+                          struct rev_info *revs, int flags,
+                          int cant_be_filename,
+                          struct object_context *a_oc,
+                          struct object_context *b_oc)
+ {
+       const char *a_name, *b_name;
+       struct object_id a_oid, b_oid;
+       struct object *a_obj, *b_obj;
+       unsigned int a_flags, b_flags;
+       int symmetric = 0;
+       unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM);
+       unsigned int oc_flags = GET_SHA1_COMMITTISH | GET_SHA1_RECORD_PATH;
+       a_name = arg;
+       if (!*a_name)
+               a_name = "HEAD";
+       b_name = dotdot + 2;
+       if (*b_name == '.') {
+               symmetric = 1;
+               b_name++;
+       }
+       if (!*b_name)
+               b_name = "HEAD";
+       if (get_sha1_with_context(a_name, oc_flags, a_oid.hash, a_oc) ||
+           get_sha1_with_context(b_name, oc_flags, b_oid.hash, b_oc))
+               return -1;
+       if (!cant_be_filename) {
+               *dotdot = '.';
+               verify_non_filename(revs->prefix, arg);
+               *dotdot = '\0';
+       }
 -              a = lookup_commit_reference(a_obj->oid.hash);
 -              b = lookup_commit_reference(b_obj->oid.hash);
++      a_obj = parse_object(&a_oid);
++      b_obj = parse_object(&b_oid);
+       if (!a_obj || !b_obj)
+               return dotdot_missing(arg, dotdot, revs, symmetric);
+       if (!symmetric) {
+               /* just A..B */
+               b_flags = flags;
+               a_flags = flags_exclude;
+       } else {
+               /* A...B -- find merge bases between the two */
+               struct commit *a, *b;
+               struct commit_list *exclude;
++              a = lookup_commit_reference(&a_obj->oid);
++              b = lookup_commit_reference(&b_obj->oid);
+               if (!a || !b)
+                       return dotdot_missing(arg, dotdot, revs, symmetric);
+               exclude = get_merge_bases(a, b);
+               add_rev_cmdline_list(revs, exclude, REV_CMD_MERGE_BASE,
+                                    flags_exclude);
+               add_pending_commit_list(revs, exclude, flags_exclude);
+               free_commit_list(exclude);
+               b_flags = flags;
+               a_flags = flags | SYMMETRIC_LEFT;
+       }
+       a_obj->flags |= a_flags;
+       b_obj->flags |= b_flags;
+       add_rev_cmdline(revs, a_obj, a_name, REV_CMD_LEFT, a_flags);
+       add_rev_cmdline(revs, b_obj, b_name, REV_CMD_RIGHT, b_flags);
+       add_pending_object_with_path(revs, a_obj, a_name, a_oc->mode, a_oc->path);
+       add_pending_object_with_path(revs, b_obj, b_name, b_oc->mode, b_oc->path);
+       return 0;
+ }
+ static int handle_dotdot(const char *arg,
+                        struct rev_info *revs, int flags,
+                        int cant_be_filename)
+ {
+       struct object_context a_oc, b_oc;
+       char *dotdot = strstr(arg, "..");
+       int ret;
+       if (!dotdot)
+               return -1;
+       memset(&a_oc, 0, sizeof(a_oc));
+       memset(&b_oc, 0, sizeof(b_oc));
+       *dotdot = '\0';
+       ret = handle_dotdot_1(arg, dotdot, revs, flags, cant_be_filename,
+                             &a_oc, &b_oc);
+       *dotdot = '.';
+       free(a_oc.path);
+       free(b_oc.path);
+       return ret;
+ }
  int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)
  {
        struct object_context oc;
-       char *dotdot;
+       char *mark;
        struct object *object;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        int local_flags;
        const char *arg = arg_;
        int cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;
        }
  
        if (revarg_opt & REVARG_COMMITTISH)
-               get_sha1_flags = GET_SHA1_COMMITTISH;
+               get_sha1_flags |= GET_SHA1_COMMITTISH;
  
 -      if (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))
 +      if (get_sha1_with_context(arg, get_sha1_flags, oid.hash, &oc))
                return revs->ignore_missing ? 0 : -1;
        if (!cant_be_filename)
                verify_non_filename(revs->prefix, arg);
 -      object = get_reference(revs, arg, sha1, flags ^ local_flags);
 +      object = get_reference(revs, arg, &oid, flags ^ local_flags);
        add_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);
-       add_pending_object_with_mode(revs, object, arg, oc.mode);
+       add_pending_object_with_path(revs, object, arg, oc.mode, oc.path);
+       free(oc.path);
        return 0;
  }
  
diff --cc sha1_name.c
Simple merge
diff --cc t/t4202-log.sh
Simple merge
diff --cc tree-walk.c
Simple merge