diff options
Diffstat (limited to 'sha1_name.c')
-rw-r--r-- | sha1_name.c | 103 |
1 files changed, 77 insertions, 26 deletions
diff --git a/sha1_name.c b/sha1_name.c index bf92417838..2c3a5fb363 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -206,7 +206,9 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len) if (exists ? !status : status == SHORT_NAME_NOT_FOUND) { - hex[len] = 0; + int cut_at = len + unique_abbrev_extra_length; + cut_at = (cut_at < 40) ? cut_at : 40; + hex[cut_at] = 0; return hex; } len++; @@ -342,7 +344,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1); static int get_sha1_basic(const char *str, int len, unsigned char *sha1) { - static const char *warning = "warning: refname '%.*s' is ambiguous.\n"; + static const char *warn_msg = "refname '%.*s' is ambiguous."; char *real_ref = NULL; int refs_found = 0; int at, reflog_len; @@ -390,7 +392,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) return -1; if (warn_ambiguous_refs && refs_found > 1) - fprintf(stderr, warning, len, str); + warning(warn_msg, len, str); if (reflog_len) { int nth, i; @@ -426,14 +428,14 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1) if (read_ref_at(real_ref, at_time, nth, sha1, NULL, &co_time, &co_tz, &co_cnt)) { if (at_time) - fprintf(stderr, - "warning: Log for '%.*s' only goes " - "back to %s.\n", len, str, + warning("Log for '%.*s' only goes " + "back to %s.", len, str, show_date(co_time, co_tz, DATE_RFC2822)); - else - fprintf(stderr, - "warning: Log for '%.*s' only has " - "%d entries.\n", len, str, co_cnt); + else { + free(real_ref); + die("Log for '%.*s' only has %d entries.", + len, str, co_cnt); + } } } @@ -659,6 +661,16 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1) return get_short_sha1(name, len, sha1, 0); } +/* + * This interprets names like ':/Initial revision of "git"' by searching + * through history and returning the first commit whose message starts + * the given regular expression. + * + * For future extension, ':/!' is reserved. If you want to match a message + * beginning with a '!', you have to repeat the exclamation mark. + */ +#define ONELINE_SEEN (1u<<20) + static int handle_one_ref(const char *path, const unsigned char *sha1, int flag, void *cb_data) { @@ -674,30 +686,26 @@ static int handle_one_ref(const char *path, if (object->type != OBJ_COMMIT) return 0; insert_by_date((struct commit *)object, list); + object->flags |= ONELINE_SEEN; return 0; } -/* - * This interprets names like ':/Initial revision of "git"' by searching - * through history and returning the first commit whose message starts - * with the given string. - * - * For future extension, ':/!' is reserved. If you want to match a message - * beginning with a '!', you have to repeat the exclamation mark. - */ - -#define ONELINE_SEEN (1u<<20) static int get_sha1_oneline(const char *prefix, unsigned char *sha1) { struct commit_list *list = NULL, *backup = NULL, *l; int retval = -1; char *temp_commit_buffer = NULL; + regex_t regex; if (prefix[0] == '!') { if (prefix[1] != '!') die ("Invalid search pattern: %s", prefix); prefix++; } + + if (regcomp(®ex, prefix, REG_EXTENDED)) + die("Invalid search pattern: %s", prefix); + for_each_ref(handle_one_ref, &list); for (l = list; l; l = l->next) commit_list_insert(l->item, &backup); @@ -721,12 +729,13 @@ static int get_sha1_oneline(const char *prefix, unsigned char *sha1) } if (!(p = strstr(p, "\n\n"))) continue; - if (!prefixcmp(p + 2, prefix)) { + if (!regexec(®ex, p + 2, 0, NULL, 0)) { hashcpy(sha1, commit->object.sha1); retval = 0; break; } } + regfree(®ex); free(temp_commit_buffer); free_commit_list(list); for (l = backup; l; l = l->next) @@ -927,14 +936,32 @@ int interpret_branch_name(const char *name, struct strbuf *buf) return len; } +int strbuf_branchname(struct strbuf *sb, const char *name) +{ + int len = strlen(name); + if (interpret_branch_name(name, sb) == len) + return 0; + strbuf_add(sb, name, len); + return len; +} + +int strbuf_check_branch_ref(struct strbuf *sb, const char *name) +{ + strbuf_branchname(sb, name); + if (name[0] == '-') + return CHECK_REF_FORMAT_ERROR; + strbuf_splice(sb, 0, 0, "refs/heads/", 11); + return check_ref_format(sb->buf); +} + /* * This is like "get_sha1_basic()", except it allows "sha1 expressions", * notably "xyz^" for "parent of xyz" */ int get_sha1(const char *name, unsigned char *sha1) { - unsigned unused; - return get_sha1_with_mode(name, sha1, &unused); + struct object_context unused; + return get_sha1_with_context(name, sha1, &unused); } /* Must be called only when object_name:filename doesn't exist. */ @@ -1032,23 +1059,37 @@ static void diagnose_invalid_index_path(int stage, int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, int gently, const char *prefix) { + struct object_context oc; + int ret; + ret = get_sha1_with_context_1(name, sha1, &oc, gently, prefix); + *mode = oc.mode; + return ret; +} + +int get_sha1_with_context_1(const char *name, unsigned char *sha1, + struct object_context *oc, + int gently, const char *prefix) +{ int ret, bracket_depth; int namelen = strlen(name); const char *cp; - *mode = S_IFINVALID; + memset(oc, 0, sizeof(*oc)); + oc->mode = S_IFINVALID; ret = get_sha1_1(name, namelen, sha1); if (!ret) return ret; /* sha1:path --> object name of path in ent sha1 * :path -> object name of path in index * :[0-3]:path -> object name of path in index at stage + * :/foo -> recent commit matching foo */ if (name[0] == ':') { int stage = 0; struct cache_entry *ce; int pos; if (namelen > 2 && name[1] == '/') + /* don't need mode for commit */ return get_sha1_oneline(name + 2, sha1); if (namelen < 3 || name[2] != ':' || @@ -1059,6 +1100,11 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, cp = name + 3; } namelen = namelen - (cp - name); + + strncpy(oc->path, cp, + sizeof(oc->path)); + oc->path[sizeof(oc->path)-1] = '\0'; + if (!active_cache) read_cache(); pos = cache_name_pos(cp, namelen); @@ -1071,7 +1117,7 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, break; if (ce_stage(ce) == stage) { hashcpy(sha1, ce->sha1); - *mode = ce->ce_mode; + oc->mode = ce->ce_mode; return 0; } pos++; @@ -1098,12 +1144,17 @@ int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode, } if (!get_sha1_1(name, cp-name, tree_sha1)) { const char *filename = cp+1; - ret = get_tree_entry(tree_sha1, filename, sha1, mode); + ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode); if (!gently) { diagnose_invalid_sha1_path(prefix, filename, tree_sha1, object_name); free(object_name); } + hashcpy(oc->tree, tree_sha1); + strncpy(oc->path, filename, + sizeof(oc->path)); + oc->path[sizeof(oc->path)-1] = '\0'; + return ret; } else { if (!gently) |