static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);
-typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);
+typedef int (*disambiguate_hint_fn)(const struct object_id *, void *);
struct disambiguate_state {
int len; /* length of prefix in hex chars */
- char hex_pfx[GIT_SHA1_HEXSZ + 1];
- unsigned char bin_pfx[GIT_SHA1_RAWSZ];
+ char hex_pfx[GIT_MAX_HEXSZ + 1];
+ struct object_id bin_pfx;
disambiguate_hint_fn fn;
void *cb_data;
- unsigned char candidate[GIT_SHA1_RAWSZ];
+ struct object_id candidate;
unsigned candidate_exists:1;
unsigned candidate_checked:1;
unsigned candidate_ok:1;
unsigned always_call_fn:1;
};
-static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)
+static void update_candidates(struct disambiguate_state *ds, const struct object_id *current)
{
if (ds->always_call_fn) {
ds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;
}
if (!ds->candidate_exists) {
/* this is the first candidate */
- hashcpy(ds->candidate, current);
+ oidcpy(&ds->candidate, current);
ds->candidate_exists = 1;
return;
- } else if (!hashcmp(ds->candidate, current)) {
+ } else if (!oidcmp(&ds->candidate, current)) {
/* the same as what we already have seen */
return;
}
}
if (!ds->candidate_checked) {
- ds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);
+ ds->candidate_ok = ds->fn(&ds->candidate, ds->cb_data);
ds->disambiguate_fn_used = 1;
ds->candidate_checked = 1;
}
if (!ds->candidate_ok) {
/* discard the candidate; we know it does not satisfy fn */
- hashcpy(ds->candidate, current);
+ oidcpy(&ds->candidate, current);
ds->candidate_checked = 0;
return;
}
static void find_short_object_filename(struct disambiguate_state *ds)
{
struct alternate_object_database *alt;
- char hex[GIT_SHA1_HEXSZ];
+ char hex[GIT_MAX_HEXSZ];
static struct alternate_object_database *fakeent;
if (!fakeent) {
continue;
while (!ds->ambiguous && (de = readdir(dir)) != NULL) {
- unsigned char sha1[20];
+ struct object_id oid;
- if (strlen(de->d_name) != 38)
+ if (strlen(de->d_name) != GIT_SHA1_HEXSZ - 2)
continue;
if (memcmp(de->d_name, ds->hex_pfx + 2, ds->len - 2))
continue;
- memcpy(hex + 2, de->d_name, 38);
- if (!get_sha1_hex(hex, sha1))
- update_candidates(ds, sha1);
+ memcpy(hex + 2, de->d_name, GIT_SHA1_HEXSZ - 2);
+ if (!get_oid_hex(hex, &oid))
+ update_candidates(ds, &oid);
}
closedir(dir);
}
struct disambiguate_state *ds)
{
uint32_t num, last, i, first = 0;
- const unsigned char *current = NULL;
+ const struct object_id *current = NULL;
open_pack_index(p);
num = p->num_objects;
int cmp;
current = nth_packed_object_sha1(p, mid);
- cmp = hashcmp(ds->bin_pfx, current);
+ cmp = hashcmp(ds->bin_pfx.hash, current);
if (!cmp) {
first = mid;
break;
* 0, 1 or more objects that actually match(es).
*/
for (i = first; i < num && !ds->ambiguous; i++) {
- current = nth_packed_object_sha1(p, i);
- if (!match_sha(ds->len, ds->bin_pfx, current))
+ struct object_id oid;
+ current = nth_packed_object_oid(&oid, p, i);
+ if (!match_sha(ds->len, ds->bin_pfx.hash, current->hash))
break;
update_candidates(ds, current);
}
* same repository!
*/
ds->candidate_ok = (!ds->disambiguate_fn_used ||
- ds->fn(ds->candidate, ds->cb_data));
+ ds->fn(&ds->candidate, ds->cb_data));
if (!ds->candidate_ok)
return SHORT_NAME_AMBIGUOUS;
- hashcpy(sha1, ds->candidate);
+ hashcpy(sha1, ds->candidate.hash);
return 0;
}
-static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_COMMIT;
}
-static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_committish_only(const struct object_id *oid, void *cb_data_unused)
{
struct object *obj;
int kind;
- kind = sha1_object_info(sha1, NULL);
+ kind = sha1_object_info(oid->hash, NULL);
if (kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(parse_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(oid->hash), NULL, 0);
if (obj && obj->type == OBJ_COMMIT)
return 1;
return 0;
}
-static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_TREE;
}
-static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_treeish_only(const struct object_id *oid, void *cb_data_unused)
{
struct object *obj;
int kind;
- kind = sha1_object_info(sha1, NULL);
+ kind = sha1_object_info(oid->hash, NULL);
if (kind == OBJ_TREE || kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
return 0;
/* We need to do this the hard way... */
- obj = deref_tag(parse_object(sha1), NULL, 0);
+ obj = deref_tag(parse_object(oid->hash), NULL, 0);
if (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))
return 1;
return 0;
}
-static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)
+static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(sha1, NULL);
+ int kind = sha1_object_info(oid->hash, NULL);
return kind == OBJ_BLOB;
}
ds->hex_pfx[i] = c;
if (!(i & 1))
val <<= 4;
- ds->bin_pfx[i >> 1] |= val;
+ ds->bin_pfx.hash[i >> 1] |= val;
}
ds->len = len;
static int show_ambiguous_object(const unsigned char *sha1, void *data)
{
const struct disambiguate_state *ds = data;
+ struct object_id oid;
struct strbuf desc = STRBUF_INIT;
int type;
- if (ds->fn && !ds->fn(sha1, ds->cb_data))
+
+ hashcpy(oid.hash, sha1);
+ if (ds->fn && !ds->fn(&oid, ds->cb_data))
return 0;
type = sha1_object_info(sha1, NULL);
return status;
}
-static int collect_ambiguous(const unsigned char *sha1, void *data)
+static int collect_ambiguous(const struct object_id *oid, void *data)
{
- sha1_array_append(data, sha1);
+ sha1_array_append(data, oid);
return 0;
}
const char *find_unique_abbrev(const unsigned char *sha1, int len)
{
static int bufno;
- static char hexbuffer[4][GIT_SHA1_HEXSZ + 1];
+ static char hexbuffer[4][GIT_MAX_HEXSZ + 1];
char *hex = hexbuffer[bufno];
bufno = (bufno + 1) % ARRAY_SIZE(hexbuffer);
find_unique_abbrev_r(hex, sha1, len);
struct strbuf buf;
};
-static int grab_nth_branch_switch(unsigned char *osha1, unsigned char *nsha1,
+static int grab_nth_branch_switch(struct object_id *ooid, struct object_id *noid,
const char *email, unsigned long timestamp, int tz,
const char *message, void *cb_data)
{
return 1;
}
-static int reinterpret(const char *name, int namelen, int len, struct strbuf *buf)
+static int reinterpret(const char *name, int namelen, int len,
+ struct strbuf *buf, unsigned allowed)
{
/* we have extra data, which might need further processing */
struct strbuf tmp = STRBUF_INIT;
int ret;
strbuf_add(buf, name + len, namelen - len);
- ret = interpret_branch_name(buf->buf, buf->len, &tmp);
+ ret = interpret_branch_name(buf->buf, buf->len, &tmp, allowed);
/* that data was not interpreted, remove our cruft */
if (ret < 0) {
strbuf_setlen(buf, used);
free(s);
}
+static int branch_interpret_allowed(const char *refname, unsigned allowed)
+{
+ if (!allowed)
+ return 1;
+
+ if ((allowed & INTERPRET_BRANCH_LOCAL) &&
+ starts_with(refname, "refs/heads/"))
+ return 1;
+ if ((allowed & INTERPRET_BRANCH_REMOTE) &&
+ starts_with(refname, "refs/remotes/"))
+ return 1;
+
+ return 0;
+}
+
static int interpret_branch_mark(const char *name, int namelen,
int at, struct strbuf *buf,
int (*get_mark)(const char *, int),
const char *(*get_data)(struct branch *,
- struct strbuf *))
+ struct strbuf *),
+ unsigned allowed)
{
int len;
struct branch *branch;
if (!value)
die("%s", err.buf);
+ if (!branch_interpret_allowed(value, allowed))
+ return -1;
+
set_shortened_ref(buf, value);
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
- * of the branch from the command line.
- *
- * - "@{-N}" finds the name of the Nth previous branch we were on, and
- * places the name of the branch in the given buf and returns the
- * number of characters parsed if successful.
- *
- * - "<branch>@{upstream}" finds the name of the other ref that
- * <branch> is configured to merge with (missing <branch> defaults
- * to the current branch), and places the name of the branch in the
- * given buf and returns the number of characters parsed if
- * successful.
- *
- * If the input is not of the accepted format, it returns a negative
- * number to signal an error.
- *
- * If the input was ok but there are not N branch switches in the
- * reflog, it returns 0.
- */
-int interpret_branch_name(const char *name, int namelen, struct strbuf *buf)
+int interpret_branch_name(const char *name, int namelen, struct strbuf *buf,
+ unsigned allowed)
{
char *at;
const char *start;
- int len = interpret_nth_prior_checkout(name, namelen, buf);
+ int len;
if (!namelen)
namelen = strlen(name);
- if (!len) {
- return len; /* syntax Ok, not enough switches */
- } else if (len > 0) {
- if (len == namelen)
- return len; /* consumed all */
- else
- return reinterpret(name, namelen, len, buf);
+ if (!allowed || (allowed & INTERPRET_BRANCH_LOCAL)) {
+ len = interpret_nth_prior_checkout(name, namelen, buf);
+ if (!len) {
+ return len; /* syntax Ok, not enough switches */
+ } else if (len > 0) {
+ if (len == namelen)
+ return len; /* consumed all */
+ else
+ return reinterpret(name, namelen, len, buf, allowed);
+ }
}
for (start = name;
(at = memchr(start, '@', namelen - (start - name)));
start = at + 1) {
- len = interpret_empty_at(name, namelen, at - name, buf);
- if (len > 0)
- return reinterpret(name, namelen, len, buf);
+ if (!allowed || (allowed & INTERPRET_BRANCH_HEAD)) {
+ len = interpret_empty_at(name, namelen, at - name, buf);
+ if (len > 0)
+ return reinterpret(name, namelen, len, buf,
+ allowed);
+ }
len = interpret_branch_mark(name, namelen, at - name, buf,
- upstream_mark, branch_get_upstream);
+ upstream_mark, branch_get_upstream,
+ allowed);
if (len > 0)
return len;
len = interpret_branch_mark(name, namelen, at - name, buf,
- push_mark, branch_get_push);
+ push_mark, branch_get_push,
+ allowed);
if (len > 0)
return len;
}
return -1;
}
-int strbuf_branchname(struct strbuf *sb, const char *name)
+void strbuf_branchname(struct strbuf *sb, const char *name, unsigned allowed)
{
int len = strlen(name);
- int used = interpret_branch_name(name, len, sb);
+ int used = interpret_branch_name(name, len, sb, allowed);
- if (used == len)
- return 0;
if (used < 0)
used = 0;
strbuf_add(sb, name + used, len - used);
- return len;
}
int strbuf_check_branch_ref(struct strbuf *sb, const char *name)
{
- strbuf_branchname(sb, name);
+ strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
if (name[0] == '-')
return -1;
strbuf_splice(sb, 0, 0, "refs/heads/", 11);