From: Junio C Hamano Date: Fri, 2 Jun 2017 06:06:05 +0000 (+0900) Subject: Merge branch 'jk/diff-blob' X-Git-Tag: v2.14.0-rc0~125 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/7ef0d047386a1932dc4a8b1008d851b0fe47f978?ds=inline;hp=-c Merge branch 'jk/diff-blob' 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 --- 7ef0d047386a1932dc4a8b1008d851b0fe47f978 diff --combined builtin/cat-file.c index 9af863e791,421709517c..73c81f0cb1 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@@ -61,7 -61,8 +61,8 @@@ static int cat_one_file(int opt, const if (unknown_type) flags |= LOOKUP_UNKNOWN_OBJECT; - if (get_sha1_with_context(obj_name, 0, oid.hash, &obj_context)) + if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH, + oid.hash, &obj_context)) die("Not a valid object name %s", obj_name); if (!path) @@@ -165,7 -166,7 +166,8 @@@ die("git cat-file %s: bad file", obj_name); write_or_die(1, buf, size); + free(buf); + free(obj_context.path); return 0; } diff --combined builtin/diff.c index 8c03ddaf58,5e7c6428c9..0c8f86e40d --- a/builtin/diff.c +++ b/builtin/diff.c @@@ -20,23 -20,22 +20,22 @@@ #define DIFF_NO_INDEX_EXPLICIT 1 #define DIFF_NO_INDEX_IMPLICIT 2 - struct blobinfo { - struct object_id oid; - const char *name; - unsigned mode; - }; - static const char builtin_diff_usage[] = "git diff [] [ []] [--] [...]"; + static const char *blob_path(struct object_array_entry *entry) + { + return entry->path ? entry->path : entry->name; + } + static void stuff_change(struct diff_options *opt, unsigned old_mode, unsigned new_mode, const struct object_id *old_oid, const struct object_id *new_oid, int old_oid_valid, int new_oid_valid, - const char *old_name, - const char *new_name) + const char *old_path, + const char *new_path) { struct diff_filespec *one, *two; @@@ -47,16 -46,16 +46,16 @@@ if (DIFF_OPT_TST(opt, REVERSE_DIFF)) { SWAP(old_mode, new_mode); SWAP(old_oid, new_oid); - SWAP(old_name, new_name); + SWAP(old_path, new_path); } if (opt->prefix && - (strncmp(old_name, opt->prefix, opt->prefix_length) || - strncmp(new_name, opt->prefix, opt->prefix_length))) + (strncmp(old_path, opt->prefix, opt->prefix_length) || + strncmp(new_path, opt->prefix, opt->prefix_length))) return; - one = alloc_filespec(old_name); - two = alloc_filespec(new_name); + one = alloc_filespec(old_path); + two = alloc_filespec(new_path); fill_filespec(one, old_oid->hash, old_oid_valid, old_mode); fill_filespec(two, new_oid->hash, new_oid_valid, new_mode); @@@ -65,7 -64,7 +64,7 @@@ static int builtin_diff_b_f(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { /* Blob vs file in the working tree*/ struct stat st; @@@ -84,14 -83,15 +83,15 @@@ diff_set_mnemonic_prefix(&revs->diffopt, "o/", "w/"); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = canon_mode(st.st_mode); + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = canon_mode(st.st_mode); stuff_change(&revs->diffopt, - blob[0].mode, canon_mode(st.st_mode), - &blob[0].oid, &null_oid, + blob[0]->mode, canon_mode(st.st_mode), + &blob[0]->item->oid, &null_oid, 1, 0, - path, path); + blob[0]->path ? blob[0]->path : path, + path); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@@ -99,24 -99,24 +99,24 @@@ static int builtin_diff_blobs(struct rev_info *revs, int argc, const char **argv, - struct blobinfo *blob) + struct object_array_entry **blob) { unsigned mode = canon_mode(S_IFREG | 0644); if (argc > 1) usage(builtin_diff_usage); - if (blob[0].mode == S_IFINVALID) - blob[0].mode = mode; + if (blob[0]->mode == S_IFINVALID) + blob[0]->mode = mode; - if (blob[1].mode == S_IFINVALID) - blob[1].mode = mode; + if (blob[1]->mode == S_IFINVALID) + blob[1]->mode = mode; stuff_change(&revs->diffopt, - blob[0].mode, blob[1].mode, - &blob[0].oid, &blob[1].oid, + blob[0]->mode, blob[1]->mode, + &blob[0]->item->oid, &blob[1]->item->oid, 1, 1, - blob[0].name, blob[1].name); + blob_path(blob[0]), blob_path(blob[1])); diffcore_std(&revs->diffopt); diff_flush(&revs->diffopt); return 0; @@@ -259,7 -259,7 +259,7 @@@ int cmd_diff(int argc, const char **arg struct rev_info rev; struct object_array ent = OBJECT_ARRAY_INIT; int blobs = 0, paths = 0; - struct blobinfo blob[2]; + struct object_array_entry *blob[2]; int nongit = 0, no_index = 0; int result = 0; @@@ -381,7 -381,7 +381,7 @@@ add_head_to_pending(&rev); if (!rev.pending.nr) { struct tree *tree; - tree = lookup_tree(EMPTY_TREE_SHA1_BIN); + tree = lookup_tree(&empty_tree_oid); add_pending_object(&rev, &tree->object, "HEAD"); } break; @@@ -395,7 -395,7 +395,7 @@@ const char *name = entry->name; int flags = (obj->flags & UNINTERESTING); if (!obj->parsed) - obj = parse_object(obj->oid.hash); + obj = parse_object(&obj->oid); obj = deref_tag(obj, NULL, 0); if (!obj) die(_("invalid object '%s' given."), name); @@@ -408,9 -408,7 +408,7 @@@ } else if (obj->type == OBJ_BLOB) { if (2 <= blobs) die(_("more than two blobs given: '%s'"), name); - oidcpy(&blob[blobs].oid, &obj->oid); - blob[blobs].name = name; - blob[blobs].mode = entry->mode; + blob[blobs] = entry; blobs++; } else { diff --combined builtin/grep.c index c6c26e9b9e,254c1c7849..72a19699a8 --- a/builtin/grep.c +++ b/builtin/grep.c @@@ -866,7 -866,7 +866,7 @@@ static int grep_directory(struct grep_o if (exc_std) setup_standard_excludes(&dir); - fill_directory(&dir, pathspec); + fill_directory(&dir, &the_index, pathspec); for (i = 0; i < dir.nr; i++) { if (!dir_path_match(dir.entries[i], pathspec, 0, NULL)) continue; @@@ -1190,16 -1190,18 +1190,18 @@@ int cmd_grep(int argc, const char **arg break; } - if (get_sha1_with_context(arg, 0, oid.hash, &oc)) { + if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH, + oid.hash, &oc)) { if (seen_dashdash) die(_("unable to resolve revision: %s"), arg); break; } - object = parse_object_or_die(oid.hash, arg); + object = parse_object_or_die(&oid, arg); if (!seen_dashdash) verify_non_filename(prefix, arg); add_object_array_with_path(object, arg, &list, oc.mode, oc.path); + free(oc.path); } /* diff --combined builtin/log.c index a440601efe,1db016bcd9..e89ec941ce --- a/builtin/log.c +++ b/builtin/log.c @@@ -110,8 -110,6 +110,8 @@@ static void init_log_defaults(void { init_grep_defaults(); init_diff_ui_defaults(); + + decoration_style = auto_decoration_style(); } static void cmd_log_init_defaults(struct rev_info *rev) @@@ -412,6 -410,8 +412,6 @@@ static int git_log_config(const char *v if (decoration_style < 0) decoration_style = 0; /* maybe warn? */ return 0; - } else { - decoration_style = auto_decoration_style(); } if (!strcmp(var, "log.showroot")) { default_show_root = git_config_bool(var, value); @@@ -483,16 -483,20 +483,20 @@@ static int show_blob_object(const struc !DIFF_OPT_TST(&rev->diffopt, ALLOW_TEXTCONV)) return stream_blob_to_fd(1, oid, NULL, 0); - if (get_sha1_with_context(obj_name, 0, oidc.hash, &obj_context)) + if (get_sha1_with_context(obj_name, GET_SHA1_RECORD_PATH, + oidc.hash, &obj_context)) die(_("Not a valid object name %s"), obj_name); - if (!obj_context.path[0] || - !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) + if (!obj_context.path || + !textconv_object(obj_context.path, obj_context.mode, &oidc, 1, &buf, &size)) { + free(obj_context.path); return stream_blob_to_fd(1, oid, NULL, 0); + } if (!buf) die(_("git show %s: bad file"), obj_name); write_or_die(1, buf, size); + free(obj_context.path); return 0; } @@@ -596,7 -600,7 +600,7 @@@ int cmd_show(int argc, const char **arg rev.shown_one = 1; if (ret) break; - o = parse_object(t->tagged->oid.hash); + o = parse_object(&t->tagged->oid); if (!o) ret = error(_("Could not read object %s"), oid_to_hex(&t->tagged->oid)); @@@ -878,8 -882,8 +882,8 @@@ static void get_patch_ids(struct rev_in o2 = rev->pending.objects[1].item; flags1 = o1->flags; flags2 = o2->flags; - c1 = lookup_commit_reference(o1->oid.hash); - c2 = lookup_commit_reference(o2->oid.hash); + c1 = lookup_commit_reference(&o1->oid); + c2 = lookup_commit_reference(&o2->oid); if ((flags1 & UNINTERESTING) == (flags2 & UNINTERESTING)) die(_("Not a range.")); @@@ -910,8 -914,8 +914,8 @@@ static void gen_message_id(struct rev_info *info, char *base) { struct strbuf buf = STRBUF_INIT; - strbuf_addf(&buf, "%s.%lu.git.%s", base, - (unsigned long) time(NULL), + strbuf_addf(&buf, "%s.%"PRItime".git.%s", base, + (timestamp_t) time(NULL), git_committer_info(IDENT_NO_NAME|IDENT_NO_DATE|IDENT_STRICT)); info->message_id = strbuf_detach(&buf, NULL); } @@@ -1263,7 -1267,7 +1267,7 @@@ static struct commit *get_base_commit(c if (get_oid(upstream, &oid)) die(_("Failed to resolve '%s' as a valid ref."), upstream); - commit = lookup_commit_or_die(oid.hash, "upstream base"); + commit = lookup_commit_or_die(&oid, "upstream base"); base_list = get_merge_bases_many(commit, total, list); /* There should be one and only one merge base. */ if (!base_list || base_list->next) @@@ -1819,7 -1823,7 +1823,7 @@@ static int add_pending_commit(const cha { struct object_id oid; if (get_oid(arg, &oid) == 0) { - struct commit *commit = lookup_commit_reference(oid.hash); + struct commit *commit = lookup_commit_reference(&oid); if (commit) { commit->object.flags |= flags; add_pending_object(revs, &commit->object, arg); diff --combined cache.h index ae4c45d379,52b91f5b64..4d92aae0e8 --- a/cache.h +++ b/cache.h @@@ -597,7 -597,6 +597,7 @@@ extern int read_index_unmerged(struct i #define CLOSE_LOCK (1 << 1) extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags); extern int discard_index(struct index_state *); +extern void move_index_extensions(struct index_state *dst, struct index_state *src); extern int unmerged_index(const struct index_state *); extern int verify_path(const char *path); extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change); @@@ -1334,13 -1333,18 +1334,18 @@@ static inline int hex2chr(const char *s struct object_context { unsigned char tree[20]; - char path[PATH_MAX]; unsigned mode; /* * symlink_path is only used by get_tree_entry_follow_symlinks, * and only for symlinks that point outside the repository. */ struct strbuf symlink_path; + /* + * If GET_SHA1_RECORD_PATH is set, this will record path (if any) + * found when resolving the name. The caller is responsible for + * releasing the memory. + */ + char *path; }; #define GET_SHA1_QUIETLY 01 @@@ -1350,6 -1354,7 +1355,7 @@@ #define GET_SHA1_TREEISH 020 #define GET_SHA1_BLOB 040 #define GET_SHA1_FOLLOW_SYMLINKS 0100 + #define GET_SHA1_RECORD_PATH 0200 #define GET_SHA1_ONLY_TO_DIE 04000 #define GET_SHA1_DISAMBIGUATORS \ @@@ -1364,7 -1369,7 +1370,7 @@@ extern int get_sha1_tree(const char *st extern int get_sha1_treeish(const char *str, unsigned char *sha1); extern int get_sha1_blob(const char *str, unsigned char *sha1); extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix); - extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc); + extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc); extern int get_oid(const char *str, struct object_id *oid); @@@ -1480,18 -1485,18 +1486,18 @@@ struct date_mode #define DATE_MODE(t) date_mode_from_type(DATE_##t) struct date_mode *date_mode_from_type(enum date_mode_type type); -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode); -void show_date_relative(unsigned long time, int tz, const struct timeval *now, +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode); +void show_date_relative(timestamp_t time, int tz, const struct timeval *now, struct strbuf *timebuf); int parse_date(const char *date, struct strbuf *out); -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset); -int parse_expiry_date(const char *date, unsigned long *timestamp); +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset); +int parse_expiry_date(const char *date, timestamp_t *timestamp); void datestamp(struct strbuf *out); #define approxidate(s) approxidate_careful((s), NULL) -unsigned long approxidate_careful(const char *, int *); -unsigned long approxidate_relative(const char *date, const struct timeval *now); +timestamp_t approxidate_careful(const char *, int *); +timestamp_t approxidate_relative(const char *date, const struct timeval *now); void parse_date_format(const char *format, struct date_mode *mode); -int date_overflows(unsigned long date); +int date_overflows(timestamp_t date); #define IDENT_STRICT 1 #define IDENT_NO_DATE 2 @@@ -2199,8 -2204,8 +2205,8 @@@ struct commit_list int try_merge_command(const char *strategy, size_t xopts_nr, const char **xopts, struct commit_list *common, const char *head_arg, struct commit_list *remotes); -int checkout_fast_forward(const unsigned char *from, - const unsigned char *to, +int checkout_fast_forward(const struct object_id *from, + const struct object_id *to, int overwrite_ignore); diff --combined revision.c index b023945309,a927d263a5..3680a43a6e --- a/revision.c +++ b/revision.c @@@ -59,10 -59,10 +59,10 @@@ static void mark_tree_contents_unintere while (tree_entry(&desc, &entry)) { switch (object_type(entry.mode)) { case OBJ_TREE: - mark_tree_uninteresting(lookup_tree(entry.oid->hash)); + mark_tree_uninteresting(lookup_tree(entry.oid)); break; case OBJ_BLOB: - mark_blob_uninteresting(lookup_blob(entry.oid->hash)); + mark_blob_uninteresting(lookup_blob(entry.oid)); break; default: /* Subproject commit - not in this repository */ @@@ -177,23 -177,23 +177,23 @@@ void add_pending_object(struct rev_inf void add_head_to_pending(struct rev_info *revs) { - unsigned char sha1[20]; + struct object_id oid; struct object *obj; - if (get_sha1("HEAD", sha1)) + if (get_oid("HEAD", &oid)) return; - obj = parse_object(sha1); + obj = parse_object(&oid); if (!obj) return; add_pending_object(revs, obj, "HEAD"); } static struct object *get_reference(struct rev_info *revs, const char *name, - const unsigned char *sha1, + const struct object_id *oid, unsigned int flags) { struct object *object; - object = parse_object(sha1); + object = parse_object(oid); if (!object) { if (revs->ignore_missing) return object; @@@ -203,10 -203,10 +203,10 @@@ return object; } -void add_pending_sha1(struct rev_info *revs, const char *name, - const unsigned char *sha1, unsigned int flags) +void add_pending_oid(struct rev_info *revs, const char *name, + const struct object_id *oid, unsigned int flags) { - struct object *object = get_reference(revs, name, sha1, flags); + struct object *object = get_reference(revs, name, oid, flags); add_pending_object(revs, object, name); } @@@ -228,9 -228,9 +228,9 @@@ static struct commit *handle_commit(str add_pending_object(revs, object, tag->tag); if (!tag->tagged) die("bad tag"); - object = parse_object(tag->tagged->oid.hash); + object = parse_object(&tag->tagged->oid); if (!object) { - if (flags & UNINTERESTING) + if (revs->ignore_missing_links || (flags & UNINTERESTING)) return NULL; die("bad object %s", oid_to_hex(&tag->tagged->oid)); } @@@ -884,7 -884,7 +884,7 @@@ static void cherry_pick_list(struct com /* How many extra uninteresting commits we want to see.. */ #define SLOP 5 -static int still_interesting(struct commit_list *src, unsigned long date, int slop, +static int still_interesting(struct commit_list *src, timestamp_t date, int slop, struct commit **interesting_cache) { /* @@@ -1018,7 -1018,7 +1018,7 @@@ static void limit_left_right(struct com static int limit_list(struct rev_info *revs) { int slop = SLOP; - unsigned long date = ~0ul; + timestamp_t date = TIME_MAX; struct commit_list *list = revs->commits; struct commit_list *newlist = NULL; struct commit_list **p = &newlist; @@@ -1157,9 -1157,9 +1157,9 @@@ static int handle_one_ref(const char *p if (ref_excluded(cb->all_revs->ref_excludes, path)) return 0; - object = get_reference(cb->all_revs, path, oid->hash, cb->all_flags); + object = get_reference(cb->all_revs, path, oid, cb->all_flags); add_rev_cmdline(cb->all_revs, object, path, REV_CMD_REF, cb->all_flags); - add_pending_sha1(cb->all_revs, path, oid->hash, cb->all_flags); + add_pending_oid(cb->all_revs, path, oid, cb->all_flags); return 0; } @@@ -1200,7 -1200,7 +1200,7 @@@ static void handle_one_reflog_commit(st { struct all_refs_cb *cb = cb_data; if (!is_null_oid(oid)) { - struct object *o = parse_object(oid->hash); + struct object *o = parse_object(oid); if (o) { o->flags |= cb->all_flags; /* ??? CMDLINEFLAGS ??? */ @@@ -1215,7 -1215,7 +1215,7 @@@ } static int handle_one_reflog_ent(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { handle_one_reflog_commit(ooid, cb_data); @@@ -1249,7 -1249,7 +1249,7 @@@ static void add_cache_tree(struct cache int i; if (it->entry_count >= 0) { - struct tree *tree = lookup_tree(it->sha1); + struct tree *tree = lookup_tree(&it->oid); add_pending_object_with_path(revs, &tree->object, "", 040000, path->buf); } @@@ -1275,7 -1275,7 +1275,7 @@@ void add_index_objects_to_pending(struc if (S_ISGITLINK(ce->ce_mode)) continue; - blob = lookup_blob(ce->oid.hash); + blob = lookup_blob(&ce->oid); if (!blob) die("unable to add index blob to traversal"); add_pending_object_with_path(revs, &blob->object, "", @@@ -1292,7 -1292,7 +1292,7 @@@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags, int exclude_parent) { - unsigned char sha1[20]; + struct object_id oid; struct object *it; struct commit *commit; struct commit_list *parents; @@@ -1303,17 -1303,17 +1303,17 @@@ flags ^= UNINTERESTING | BOTTOM; arg++; } - if (get_sha1_committish(arg, sha1)) + if (get_sha1_committish(arg, oid.hash)) return 0; while (1) { - it = get_reference(revs, arg, sha1, 0); + it = get_reference(revs, arg, &oid, 0); if (!it && revs->ignore_missing) return 0; if (it->type != OBJ_TAG) break; if (!((struct tag*)it)->tagged) return 0; - hashcpy(sha1, ((struct tag*)it)->tagged->oid.hash); + oidcpy(&oid, &((struct tag*)it)->tagged->oid); } if (it->type != OBJ_COMMIT) return 0; @@@ -1389,16 -1389,16 +1389,16 @@@ static void prepare_show_merge(struct r { struct commit_list *bases; struct commit *head, *other; - unsigned char sha1[20]; + struct object_id oid; const char **prune = NULL; int i, prune_num = 1; /* counting terminating NULL */ - if (get_sha1("HEAD", sha1)) + if (get_oid("HEAD", &oid)) die("--merge without HEAD?"); - head = lookup_commit_or_die(sha1, "HEAD"); - if (get_sha1("MERGE_HEAD", sha1)) + head = lookup_commit_or_die(&oid, "HEAD"); + if (get_oid("MERGE_HEAD", &oid)) die("--merge without MERGE_HEAD?"); - other = lookup_commit_or_die(sha1, "MERGE_HEAD"); + other = lookup_commit_or_die(&oid, "MERGE_HEAD"); add_pending_object(revs, &head->object, "HEAD"); add_pending_object(revs, &other->object, "MERGE_HEAD"); bases = get_merge_bases(head, other); @@@ -1429,134 -1429,168 +1429,168 @@@ revs->limited = 1; } + 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_obj = parse_object(a_oid.hash); - b_obj = parse_object(b_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.hash); - b = lookup_commit_reference(b_obj->oid.hash); ++ 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; - unsigned get_sha1_flags = 0; + unsigned get_sha1_flags = GET_SHA1_RECORD_PATH; flags = flags & UNINTERESTING ? flags | BOTTOM : flags & ~BOTTOM; - dotdot = strstr(arg, ".."); - if (dotdot) { - struct object_id from_oid; - const char *next = dotdot + 2; - const char *this = arg; - int symmetric = *next == '.'; - unsigned int flags_exclude = flags ^ (UNINTERESTING | BOTTOM); - static const char head_by_default[] = "HEAD"; - unsigned int a_flags; - - *dotdot = 0; - next += symmetric; - - if (!*next) - next = head_by_default; - if (dotdot == arg) - this = head_by_default; - if (this == head_by_default && next == head_by_default && - !symmetric) { - /* - * Just ".."? That is not a range but the - * pathspec for the parent directory. - */ - if (!cant_be_filename) { - *dotdot = '.'; - return -1; - } - } - if (!get_sha1_committish(this, from_oid.hash) && - !get_sha1_committish(next, oid.hash)) { - struct object *a_obj, *b_obj; - - if (!cant_be_filename) { - *dotdot = '.'; - verify_non_filename(revs->prefix, arg); - } - - a_obj = parse_object(&from_oid); - b_obj = parse_object(&oid); - if (!a_obj || !b_obj) { - missing: - if (revs->ignore_missing) - return 0; - die(symmetric - ? "Invalid symmetric difference expression %s" - : "Invalid revision range %s", arg); - } - - if (!symmetric) { - /* just A..B */ - a_flags = flags_exclude; - } else { - /* A...B -- find merge bases between the two */ - struct commit *a, *b; - struct commit_list *exclude; - - a = (a_obj->type == OBJ_COMMIT - ? (struct commit *)a_obj - : lookup_commit_reference(&a_obj->oid)); - b = (b_obj->type == OBJ_COMMIT - ? (struct commit *)b_obj - : lookup_commit_reference(&b_obj->oid)); - if (!a || !b) - goto missing; - 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); - - a_flags = flags | SYMMETRIC_LEFT; - } - - a_obj->flags |= a_flags; - b_obj->flags |= flags; - add_rev_cmdline(revs, a_obj, this, - REV_CMD_LEFT, a_flags); - add_rev_cmdline(revs, b_obj, next, - REV_CMD_RIGHT, flags); - add_pending_object(revs, a_obj, this); - add_pending_object(revs, b_obj, next); - return 0; - } - *dotdot = '.'; + if (!cant_be_filename && !strcmp(arg, "..")) { + /* + * Just ".."? That is not a range but the + * pathspec for the parent directory. + */ + return -1; } - dotdot = strstr(arg, "^@"); - if (dotdot && !dotdot[2]) { - *dotdot = 0; + if (!handle_dotdot(arg, revs, flags, revarg_opt)) + return 0; + + mark = strstr(arg, "^@"); + if (mark && !mark[2]) { + *mark = 0; if (add_parents_only(revs, arg, flags, 0)) return 0; - *dotdot = '^'; + *mark = '^'; } - dotdot = strstr(arg, "^!"); - if (dotdot && !dotdot[2]) { - *dotdot = 0; + mark = strstr(arg, "^!"); + if (mark && !mark[2]) { + *mark = 0; if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), 0)) - *dotdot = '^'; + *mark = '^'; } - dotdot = strstr(arg, "^-"); - if (dotdot) { + mark = strstr(arg, "^-"); + if (mark) { int exclude_parent = 1; - if (dotdot[2]) { + if (mark[2]) { char *end; - exclude_parent = strtoul(dotdot + 2, &end, 10); + exclude_parent = strtoul(mark + 2, &end, 10); if (*end != '\0' || !exclude_parent) return -1; } - *dotdot = 0; + *mark = 0; if (!add_parents_only(revs, arg, flags ^ (UNINTERESTING | BOTTOM), exclude_parent)) - *dotdot = '^'; + *mark = '^'; } local_flags = 0; @@@ -1566,15 -1600,16 +1600,16 @@@ } 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; } @@@ -2287,12 -2322,12 +2322,12 @@@ int setup_revisions(int argc, const cha if (revs->show_merge) prepare_show_merge(revs); if (revs->def && !revs->pending.nr && !got_rev_arg) { - unsigned char sha1[20]; + struct object_id oid; struct object *object; struct object_context oc; - if (get_sha1_with_context(revs->def, 0, sha1, &oc)) + if (get_sha1_with_context(revs->def, 0, oid.hash, &oc)) diagnose_missing_default(revs->def); - object = get_reference(revs, revs->def, sha1, 0); + object = get_reference(revs, revs->def, &oid, 0); add_pending_object_with_mode(revs, object, revs->def, oc.mode); } diff --combined sha1_name.c index 389276e9d3,5e2ec37b65..e9ffe685d5 --- a/sha1_name.c +++ b/sha1_name.c @@@ -241,7 -241,7 +241,7 @@@ static int disambiguate_committish_only return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && obj->type == OBJ_COMMIT) return 1; return 0; @@@ -265,7 -265,7 +265,7 @@@ static int disambiguate_treeish_only(co return 0; /* We need to do this the hard way... */ - obj = deref_tag(parse_object(oid->hash), NULL, 0); + obj = deref_tag(parse_object(oid), NULL, 0); if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT)) return 1; return 0; @@@ -354,14 -354,14 +354,14 @@@ static int show_ambiguous_object(const type = sha1_object_info(oid->hash, NULL); if (type == OBJ_COMMIT) { - struct commit *commit = lookup_commit(oid->hash); + struct commit *commit = lookup_commit(oid); if (commit) { struct pretty_print_context pp = {0}; pp.date_mode.type = DATE_SHORT; format_commit_message(commit, " %ad - %s", &desc, &pp); } } else if (type == OBJ_TAG) { - struct tag *tag = lookup_tag(oid->hash); + struct tag *tag = lookup_tag(oid); if (!parse_tag(tag) && tag->tag) strbuf_addf(&desc, " %s", tag->tag); } @@@ -660,8 -660,8 +660,8 @@@ static int get_sha1_basic(const char *s if (reflog_len) { int nth, i; - unsigned long at_time; - unsigned long co_time; + timestamp_t at_time; + timestamp_t co_time; int co_tz, co_cnt; /* Is it asking for N-th entry, or approxidate? */ @@@ -722,14 -722,14 +722,14 @@@ static int get_parent(const char *name, int len, unsigned char *result, int idx) { - unsigned char sha1[20]; - int ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + struct object_id oid; + int ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); struct commit *commit; struct commit_list *p; if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (parse_commit(commit)) return -1; if (!idx) { @@@ -750,14 -750,14 +750,14 @@@ static int get_nth_ancestor(const char *name, int len, unsigned char *result, int generation) { - unsigned char sha1[20]; + struct object_id oid; struct commit *commit; int ret; - ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH); + ret = get_sha1_1(name, len, oid.hash, GET_SHA1_COMMITTISH); if (ret) return ret; - commit = lookup_commit_reference(sha1); + commit = lookup_commit_reference(&oid); if (!commit) return -1; @@@ -776,7 -776,7 +776,7 @@@ struct object *peel_to_type(const char if (name && !namelen) namelen = strlen(name); while (1) { - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return NULL; if (expected_type == OBJ_ANY || o->type == expected_type) return o; @@@ -798,7 -798,7 +798,7 @@@ static int peel_onion(const char *name, int len, unsigned char *sha1, unsigned lookup_flags) { - unsigned char outer[20]; + struct object_id outer; const char *sp; unsigned int expected_type = 0; struct object *o; @@@ -846,15 -846,15 +846,15 @@@ else if (expected_type == OBJ_TREE) lookup_flags |= GET_SHA1_TREEISH; - if (get_sha1_1(name, sp - name - 2, outer, lookup_flags)) + if (get_sha1_1(name, sp - name - 2, outer.hash, lookup_flags)) return -1; - o = parse_object(outer); + o = parse_object(&outer); if (!o) return -1; if (!expected_type) { o = deref_tag(o, name, sp - name - 2); - if (!o || (!o->parsed && !parse_object(o->oid.hash))) + if (!o || (!o->parsed && !parse_object(&o->oid))) return -1; hashcpy(sha1, o->oid.hash); return 0; @@@ -981,7 -981,7 +981,7 @@@ static int handle_one_ref(const char *p int flag, void *cb_data) { struct commit_list **list = cb_data; - struct object *object = parse_object(oid->hash); + struct object *object = parse_object(oid); if (!object) return 0; if (object->type == OBJ_TAG) { @@@ -1027,7 -1027,7 +1027,7 @@@ static int get_sha1_oneline(const char int matches; commit = pop_most_recent_commit(&list, ONELINE_SEEN); - if (!parse_object(commit->object.oid.hash)) + if (!parse_object(&commit->object.oid)) continue; buf = get_commit_buffer(commit, NULL); p = strstr(buf, "\n\n"); @@@ -1054,7 -1054,7 +1054,7 @@@ struct grab_nth_branch_switch_cbdata }; static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid, - const char *email, unsigned long timestamp, int tz, + const char *email, timestamp_t timestamp, int tz, const char *message, void *cb_data) { struct grab_nth_branch_switch_cbdata *cb = cb_data; @@@ -1136,13 -1136,13 +1136,13 @@@ int get_oid_mb(const char *name, struc } if (st) return st; - one = lookup_commit_reference_gently(oid_tmp.hash, 0); + one = lookup_commit_reference_gently(&oid_tmp, 0); if (!one) return -1; if (get_sha1_committish(dots[3] ? (dots + 3) : "HEAD", oid_tmp.hash)) return -1; - two = lookup_commit_reference_gently(oid_tmp.hash, 0); + two = lookup_commit_reference_gently(&oid_tmp, 0); if (!two) return -1; mbs = get_merge_bases(one, two); @@@ -1511,6 -1511,7 +1511,7 @@@ static int get_sha1_with_context_1(cons memset(oc, 0, sizeof(*oc)); oc->mode = S_IFINVALID; + strbuf_init(&oc->symlink_path, 0); ret = get_sha1_1(name, namelen, sha1, flags); if (!ret) return ret; @@@ -1549,7 -1550,8 +1550,8 @@@ namelen = strlen(cp); } - strlcpy(oc->path, cp, sizeof(oc->path)); + if (flags & GET_SHA1_RECORD_PATH) + oc->path = xstrdup(cp); if (!active_cache) read_cache(); @@@ -1612,7 -1614,8 +1614,8 @@@ } } hashcpy(oc->tree, tree_sha1); - strlcpy(oc->path, filename, sizeof(oc->path)); + if (flags & GET_SHA1_RECORD_PATH) + oc->path = xstrdup(filename); free(new_filename); return ret; @@@ -1638,9 -1641,9 +1641,9 @@@ void maybe_die_on_misspelt_object_name( get_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc); } - int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc) + int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc) { if (flags & GET_SHA1_FOLLOW_SYMLINKS && flags & GET_SHA1_ONLY_TO_DIE) die("BUG: incompatible flags for get_sha1_with_context"); - return get_sha1_with_context_1(str, flags, NULL, sha1, orc); + return get_sha1_with_context_1(str, flags, NULL, sha1, oc); } diff --combined t/t4202-log.sh index 6499cdf6ff,6da1bbe912..e4441957e2 --- a/t/t4202-log.sh +++ b/t/t4202-log.sh @@@ -399,7 -399,7 +399,7 @@@ cat > expect <<\EO | | | | Merge branch 'side' | | -| * commit side +| * commit tags/side-2 | | Author: A U Thor | | | | side-2 @@@ -577,18 -577,6 +577,18 @@@ test_expect_success 'log.decorate confi ' +test_expect_success 'log.decorate config parsing' ' + git log --oneline --decorate=full >expect.full && + git log --oneline --decorate=short >expect.short && + + test_config log.decorate full && + test_config log.mailmap true && + git log --oneline >actual && + test_cmp expect.full actual && + git log --oneline --decorate=short >actual && + test_cmp expect.short actual +' + test_expect_success TTY 'log output on a TTY' ' git log --oneline --decorate >expect.short && @@@ -1392,4 -1380,13 +1392,13 @@@ test_expect_success 'log --source paint test_cmp expect actual ' + test_expect_success 'log --source paints symmetric ranges' ' + cat >expect <<-\EOF && + 09e12a9 source-b three + 8e393e1 source-a two + EOF + git log --oneline --source source-a...source-b >actual && + test_cmp expect actual + ' + test_done diff --combined tree-walk.c index f25a08fddf,c7ecfc8560..6a42e402b0 --- a/tree-walk.c +++ b/tree-walk.c @@@ -589,7 -589,6 +589,6 @@@ enum follow_symlinks_result get_tree_en int i; init_tree_desc(&t, NULL, 0UL); - strbuf_init(result_path, 0); strbuf_addstr(&namebuf, name); hashcpy(current_tree_sha1, tree_sha1); @@@ -1075,7 -1074,7 +1074,7 @@@ match_wildcards * later on. * max_depth is ignored but we may consider support it * in future, see - * http://thread.gmane.org/gmane.comp.version-control.git/163757/focus=163840 + * https://public-inbox.org/git/7vmxo5l2g4.fsf@alter.siamese.dyndns.org/ */ if (ps->recursive && S_ISDIR(entry->mode)) return entry_interesting;