unsigned candidate_ok:1;
unsigned disambiguate_fn_used:1;
unsigned ambiguous:1;
+ unsigned always_call_fn:1;
};
static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
{
+ if (ds->always_call_fn) {
+ ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
+ return;
+ }
if (!ds->candidate_exists) {
/* this is the first candidate */
hashcpy(ds->candidate, current);
return kind == OBJ_BLOB;
}
-static int get_short_sha1(const char *name, int len, unsigned char *sha1,
- unsigned flags)
+static int prepare_prefixes(const char *name, int len,
+ unsigned char *bin_pfx,
+ char *hex_pfx)
{
- int i, status;
- char hex_pfx[40];
- unsigned char bin_pfx[20];
- struct disambiguate_state ds;
- int quietly = !!(flags & GET_SHA1_QUIETLY);
+ int i;
- if (len < MINIMUM_ABBREV || len > 40)
- return -1;
hashclr(bin_pfx);
memset(hex_pfx, 'x', 40);
for (i = 0; i < len ;i++) {
val <<= 4;
bin_pfx[i >> 1] |= val;
}
+ return 0;
+}
+
+static int get_short_sha1(const char *name, int len, unsigned char *sha1,
+ unsigned flags)
+{
+ int status;
+ char hex_pfx[40];
+ unsigned char bin_pfx[20];
+ struct disambiguate_state ds;
+ int quietly = !!(flags & GET_SHA1_QUIETLY);
+
+ if (len < MINIMUM_ABBREV || len > 40)
+ return -1;
+ if (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)
+ return -1;
prepare_alt_odb();
return status;
}
+
+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)
+{
+ char hex_pfx[40];
+ unsigned char bin_pfx[20];
+ struct disambiguate_state ds;
+ int len = strlen(prefix);
+
+ if (len < MINIMUM_ABBREV || len > 40)
+ return -1;
+ if (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)
+ return -1;
+
+ prepare_alt_odb();
+
+ memset(&ds, 0, sizeof(ds));
+ ds.always_call_fn = 1;
+ ds.cb_data = cb_data;
+ ds.fn = fn;
+
+ find_short_object_filename(len, hex_pfx, &ds);
+ find_short_packed_object(len, bin_pfx, &ds);
+ return ds.ambiguous;
+}
+
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
int status, exists;
}
struct grab_nth_branch_switch_cbdata {
- long cnt, alloc;
- struct strbuf *buf;
+ int remaining;
+ struct strbuf buf;
};
static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
struct grab_nth_branch_switch_cbdata *cb = cb_data;
const char *match = NULL, *target = NULL;
size_t len;
- int nth;
if (!prefixcmp(message, "checkout: moving from ")) {
match = message + strlen("checkout: moving from ");
if (!match || !target)
return 0;
-
- len = target - match;
- nth = cb->cnt++ % cb->alloc;
- strbuf_reset(&cb->buf[nth]);
- strbuf_add(&cb->buf[nth], match, len);
+ if (--(cb->remaining) == 0) {
+ len = target - match;
+ strbuf_reset(&cb->buf);
+ strbuf_add(&cb->buf, match, len);
+ return 1; /* we are done */
+ }
return 0;
}
static int interpret_nth_prior_checkout(const char *name, struct strbuf *buf)
{
long nth;
- int i, retval;
+ int retval;
struct grab_nth_branch_switch_cbdata cb;
const char *brace;
char *num_end;
brace = strchr(name, '}');
if (!brace)
return -1;
- nth = strtol(name+3, &num_end, 10);
+ nth = strtol(name + 3, &num_end, 10);
if (num_end != brace)
return -1;
if (nth <= 0)
return -1;
- cb.alloc = nth;
- cb.buf = xmalloc(nth * sizeof(struct strbuf));
- for (i = 0; i < nth; i++)
- strbuf_init(&cb.buf[i], 20);
- cb.cnt = 0;
+ cb.remaining = nth;
+ strbuf_init(&cb.buf, 20);
+
retval = 0;
- for_each_recent_reflog_ent("HEAD", grab_nth_branch_switch, 40960, &cb);
- if (cb.cnt < nth) {
- cb.cnt = 0;
- for_each_reflog_ent("HEAD", grab_nth_branch_switch, &cb);
+ 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);
+ retval = brace - name + 1;
}
- if (cb.cnt < nth)
- goto release_return;
- i = cb.cnt % nth;
- strbuf_reset(buf);
- strbuf_add(buf, cb.buf[i].buf, cb.buf[i].len);
- retval = brace-name+1;
-
-release_return:
- for (i = 0; i < nth; i++)
- strbuf_release(&cb.buf[i]);
- free(cb.buf);
+ strbuf_release(&cb.buf);
return retval;
}
len = cp + tmp_len - name;
cp = xstrndup(name, cp - name);
upstream = branch_get(*cp ? cp : NULL);
- if (!upstream
- || !upstream->merge
- || !upstream->merge[0]->dst)
- return error("No upstream branch found for '%s'", cp);
+ /*
+ * Upstream can be NULL only if cp refers to HEAD and HEAD
+ * points to something different than a branch.
+ */
+ if (!upstream)
+ return error(_("HEAD does not point to a branch"));
+ if (!upstream->merge || !upstream->merge[0]->dst) {
+ if (!ref_exists(upstream->refname))
+ return error(_("No such branch: '%s'"), cp);
+ if (!upstream->merge)
+ return error(_("No upstream configured for branch '%s'"),
+ upstream->name);
+ return error(
+ _("Upstream branch '%s' not stored as a remote-tracking branch"),
+ upstream->merge[0]->src);
+ }
free(cp);
cp = shorten_unambiguous_ref(upstream->merge[0]->dst, 0);
strbuf_reset(buf);
if (new_filename)
filename = new_filename;
ret = get_tree_entry(tree_sha1, filename, sha1, &oc->mode);
- if (only_to_die) {
+ if (ret && only_to_die) {
diagnose_invalid_sha1_path(prefix, filename,
tree_sha1, object_name);
free(object_name);