}
static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned lookup_flags);
-static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf);
+static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
-static int get_sha1_basic(const char *str, int len, unsigned char *sha1)
+static int get_sha1_basic(const char *str, int len, unsigned char *sha1,
+ unsigned int flags)
{
static const char *warn_msg = "refname '%.*s' is ambiguous.";
static const char *object_name_msg = N_(
struct strbuf buf = STRBUF_INIT;
int detached;
- if (interpret_nth_prior_checkout(str, &buf) > 0) {
+ if (interpret_nth_prior_checkout(str, len, &buf) > 0) {
detached = (buf.len == 40 && !get_sha1_hex(buf.buf, sha1));
strbuf_release(&buf);
if (detached)
if (!refs_found)
return -1;
- if (warn_ambiguous_refs &&
+ if (warn_ambiguous_refs && !(flags & GET_SHA1_QUIETLY) &&
(refs_found > 1 ||
!get_short_sha1(str, len, tmp_sha1, GET_SHA1_QUIETLY)))
warning(warn_msg, len, str);
char *tmp = xstrndup(str + at + 2, reflog_len);
at_time = approxidate_careful(tmp, &errors);
free(tmp);
- if (errors)
+ if (errors) {
+ free(real_ref);
return -1;
+ }
}
- if (read_ref_at(real_ref, at_time, nth, sha1, NULL,
+ if (read_ref_at(real_ref, flags, at_time, nth, sha1, NULL,
&co_time, &co_tz, &co_cnt)) {
if (!len) {
if (starts_with(real_ref, "refs/heads/")) {
len = 4;
}
}
- if (at_time)
- warning("Log for '%.*s' only goes "
- "back to %s.", len, str,
- show_date(co_time, co_tz, DATE_RFC2822));
- else {
+ if (at_time) {
+ if (!(flags & GET_SHA1_QUIETLY)) {
+ warning("Log for '%.*s' only goes "
+ "back to %s.", len, str,
+ show_date(co_time, co_tz, DATE_RFC2822));
+ }
+ } else {
+ if (flags & GET_SHA1_QUIETLY) {
+ exit(128);
+ }
die("Log for '%.*s' only has %d entries.",
len, str, co_cnt);
}
if (!ret)
return 0;
- ret = get_sha1_basic(name, len, sha1);
+ ret = get_sha1_basic(name, len, sha1, lookup_flags);
if (!ret)
return 0;
* For future extension, ':/!' is reserved. If you want to match a message
* beginning with a '!', you have to repeat the exclamation mark.
*/
+
+/* Remember to update object flag allocation in object.h */
#define ONELINE_SEEN (1u<<20)
static int handle_one_ref(const char *path,
}
if (object->type != OBJ_COMMIT)
return 0;
- commit_list_insert_by_date((struct commit *)object, list);
+ commit_list_insert((struct commit *)object, list);
return 0;
}
commit_list_insert(l->item, &backup);
}
while (list) {
- char *p, *to_free = NULL;
+ const char *p, *buf;
struct commit *commit;
- enum object_type type;
- unsigned long size;
int matches;
commit = pop_most_recent_commit(&list, ONELINE_SEEN);
if (!parse_object(commit->object.sha1))
continue;
- if (commit->buffer)
- p = commit->buffer;
- else {
- p = read_sha1_file(commit->object.sha1, &type, &size);
- if (!p)
- continue;
- to_free = p;
- }
-
- p = strstr(p, "\n\n");
+ buf = get_commit_buffer(commit, NULL);
+ p = strstr(buf, "\n\n");
matches = p && !regexec(®ex, p + 2, 0, NULL, 0);
- free(to_free);
+ unuse_commit_buffer(commit, buf);
if (matches) {
hashcpy(sha1, commit->object.sha1);
const char *match = NULL, *target = NULL;
size_t len;
- if (starts_with(message, "checkout: moving from ")) {
- match = message + strlen("checkout: moving from ");
+ if (skip_prefix(message, "checkout: moving from ", &match))
target = strstr(match, " to ");
- }
if (!match || !target)
return 0;
* Parse @{-N} syntax, return the number of characters parsed
* if successful; otherwise signal an error with negative value.
*/
-static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
+static int interpret_nth_prior_checkout(const char *name, int namelen,
+ struct strbuf *buf)
{
long nth;
int retval;
const char *brace;
char *num_end;
+ if (namelen < 4)
+ return -1;
if (name[0] != '@' || name[1] != '{' || name[2] != '-')
return -1;
- brace = strchr(name, '}');
+ brace = memchr(name, '}', namelen);
if (!brace)
return -1;
nth = strtol(name + 3, &num_end, 10);
retval = 0;
if (0 < for_each_reflog_ent_reverse("HEAD", grab_nth_branch_switch, &cb)) {
strbuf_reset(buf);
- strbuf_add(buf, cb.buf.buf, cb.buf.len);
+ strbuf_addbuf(buf, &cb.buf);
retval = brace - name + 1;
}
return -1;
/* make sure it's a single @, or @@{.*}, not @foo */
- next = strchr(name + len + 1, '@');
+ next = memchr(name + len + 1, '@', namelen - len - 1);
if (next && next[1] != '{')
return -1;
if (!next)
return ret - used + len;
}
+static void set_shortened_ref(struct strbuf *buf, const char *ref)
+{
+ char *s = shorten_unambiguous_ref(ref, 0);
+ strbuf_reset(buf);
+ strbuf_addstr(buf, s);
+ free(s);
+}
+
+static const char *get_upstream_branch(const char *branch_buf, int len)
+{
+ char *branch = xstrndup(branch_buf, len);
+ struct branch *upstream = branch_get(*branch ? branch : NULL);
+
+ /*
+ * Upstream can be NULL only if branch refers to HEAD and HEAD
+ * points to something different than a branch.
+ */
+ if (!upstream)
+ die(_("HEAD does not point to a branch"));
+ if (!upstream->merge || !upstream->merge[0]->dst) {
+ if (!ref_exists(upstream->refname))
+ die(_("No such branch: '%s'"), branch);
+ if (!upstream->merge) {
+ die(_("No upstream configured for branch '%s'"),
+ upstream->name);
+ }
+ die(
+ _("Upstream branch '%s' not stored as a remote-tracking branch"),
+ upstream->merge[0]->src);
+ }
+ free(branch);
+
+ return upstream->merge[0]->dst;
+}
+
+static int interpret_upstream_mark(const char *name, int namelen,
+ int at, struct strbuf *buf)
+{
+ int len;
+
+ len = upstream_mark(name + at, namelen - at);
+ if (!len)
+ return -1;
+
+ if (memchr(name, ':', at))
+ return -1;
+
+ set_shortened_ref(buf, get_upstream_branch(name, at));
+ return len + at;
+}
+
/*
* This reads short-hand syntax that not only evaluates to a commit
* object name, but also can act as if the end user spelled the name
*/
int interpret_branch_name(const char *name, int namelen, struct strbuf *buf)
{
- char *cp;
- struct branch *upstream;
- int len = interpret_nth_prior_checkout(name, buf);
- int tmp_len;
+ char *at;
+ const char *start;
+ int len = interpret_nth_prior_checkout(name, namelen, buf);
if (!namelen)
namelen = strlen(name);
return reinterpret(name, namelen, len, buf);
}
- cp = strchr(name, '@');
- if (!cp)
- return -1;
-
- len = interpret_empty_at(name, namelen, cp - name, buf);
- if (len > 0)
- return reinterpret(name, namelen, len, buf);
+ for (start = name;
+ (at = memchr(start, '@', namelen - (start - name)));
+ start = at + 1) {
- tmp_len = upstream_mark(cp, namelen - (cp - name));
- if (!tmp_len)
- return -1;
+ len = interpret_empty_at(name, namelen, at - name, buf);
+ if (len > 0)
+ return reinterpret(name, namelen, len, buf);
- len = cp + tmp_len - name;
- cp = xstrndup(name, cp - name);
- upstream = branch_get(*cp ? cp : NULL);
- /*
- * Upstream can be NULL only if cp refers to HEAD and HEAD
- * points to something different than a branch.
- */
- if (!upstream)
- die(_("HEAD does not point to a branch"));
- if (!upstream->merge || !upstream->merge[0]->dst) {
- if (!ref_exists(upstream->refname))
- die(_("No such branch: '%s'"), cp);
- if (!upstream->merge) {
- die(_("No upstream configured for branch '%s'"),
- upstream->name);
- }
- die(
- _("Upstream branch '%s' not stored as a remote-tracking branch"),
- upstream->merge[0]->src);
+ len = interpret_upstream_mark(name, namelen, at - name, buf);
+ if (len > 0)
+ return len;
}
- free(cp);
- cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);
- strbuf_reset(buf);
- strbuf_addstr(buf, cp);
- free(cp);
- return len;
+
+ return -1;
}
int strbuf_branchname(struct strbuf *sb, const char *name)
die("Path '%s' exists on disk, but not in '%.*s'.",
filename, object_name_len, object_name);
if (errno == ENOENT || errno == ENOTDIR) {
- char *fullname = xmalloc(strlen(filename)
- + strlen(prefix) + 1);
- strcpy(fullname, prefix);
- strcat(fullname, filename);
+ char *fullname = xstrfmt("%s%s", prefix, filename);
if (!get_tree_entry(tree_sha1, fullname,
sha1, &mode)) {
if (!only_to_die && namelen > 2 && name[1] == '/') {
struct commit_list *list = NULL;
for_each_ref(handle_one_ref, &list);
+ commit_list_sort_by_date(&list);
return get_sha1_oneline(name + 2, sha1, list);
}
if (namelen < 3 ||