#include "dir.h"
#include "sha1-array.h"
#include "packfile.h"
+#include "object-store.h"
+#include "repository.h"
static int get_oid_oneline(const char *, struct object_id *, struct commit_list *);
*/
fakeent = alloc_alt_odb(get_object_directory());
}
- fakeent->next = alt_odb_list;
+ fakeent->next = the_repository->objects->alt_odb_list;
for (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {
int pos;
static void unique_in_pack(struct packed_git *p,
struct disambiguate_state *ds)
{
- uint32_t num, last, i, first = 0;
+ uint32_t num, i, first = 0;
const struct object_id *current = NULL;
- open_pack_index(p);
+ if (open_pack_index(p) || !p->num_objects)
+ return;
+
num = p->num_objects;
- last = num;
- while (first < last) {
- uint32_t mid = first + (last - first) / 2;
- const unsigned char *current;
- int cmp;
-
- current = nth_packed_object_sha1(p, mid);
- cmp = hashcmp(ds->bin_pfx.hash, current);
- if (!cmp) {
- first = mid;
- break;
- }
- if (cmp > 0) {
- first = mid+1;
- continue;
- }
- last = mid;
- }
+ bsearch_pack(&ds->bin_pfx, p, &first);
/*
* At this point, "first" is the location of the lowest object
{
struct packed_git *p;
- prepare_packed_git();
- for (p = packed_git; p && !ds->ambiguous; p = p->next)
+ for (p = get_packed_git(the_repository); p && !ds->ambiguous;
+ p = p->next)
unique_in_pack(p, ds);
}
static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(oid->hash, NULL);
+ int kind = oid_object_info(oid, NULL);
return kind == OBJ_COMMIT;
}
struct object *obj;
int kind;
- kind = sha1_object_info(oid->hash, NULL);
+ kind = oid_object_info(oid, NULL);
if (kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
static int disambiguate_tree_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(oid->hash, NULL);
+ int kind = oid_object_info(oid, NULL);
return kind == OBJ_TREE;
}
struct object *obj;
int kind;
- kind = sha1_object_info(oid->hash, NULL);
+ kind = oid_object_info(oid, NULL);
if (kind == OBJ_TREE || kind == OBJ_COMMIT)
return 1;
if (kind != OBJ_TAG)
static int disambiguate_blob_only(const struct object_id *oid, void *cb_data_unused)
{
- int kind = sha1_object_info(oid->hash, NULL);
+ int kind = oid_object_info(oid, NULL);
return kind == OBJ_BLOB;
}
ds->len = len;
ds->hex_pfx[len] = '\0';
- prepare_alt_odb();
+ prepare_alt_odb(the_repository);
return 0;
}
if (ds->fn && !ds->fn(oid, ds->cb_data))
return 0;
- type = sha1_object_info(oid->hash, NULL);
+ type = oid_object_info(oid, NULL);
if (type == OBJ_COMMIT) {
struct commit *commit = lookup_commit(oid);
if (commit) {
}
advise(" %s %s%s",
- find_unique_abbrev(oid->hash, DEFAULT_ABBREV),
- typename(type) ? typename(type) : "unknown type",
+ find_unique_abbrev(oid, DEFAULT_ABBREV),
+ type_name(type) ? type_name(type) : "unknown type",
desc.buf);
strbuf_release(&desc);
return r;
}
-int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len)
+struct min_abbrev_data {
+ unsigned int init_len;
+ unsigned int cur_len;
+ char *hex;
+ const struct object_id *oid;
+};
+
+static inline char get_hex_char_from_oid(const struct object_id *oid,
+ unsigned int pos)
+{
+ static const char hex[] = "0123456789abcdef";
+
+ if ((pos & 1) == 0)
+ return hex[oid->hash[pos >> 1] >> 4];
+ else
+ return hex[oid->hash[pos >> 1] & 0xf];
+}
+
+static int extend_abbrev_len(const struct object_id *oid, void *cb_data)
+{
+ struct min_abbrev_data *mad = cb_data;
+
+ unsigned int i = mad->init_len;
+ while (mad->hex[i] && mad->hex[i] == get_hex_char_from_oid(oid, i))
+ i++;
+
+ if (i < GIT_MAX_RAWSZ && i >= mad->cur_len)
+ mad->cur_len = i + 1;
+
+ return 0;
+}
+
+static void find_abbrev_len_for_pack(struct packed_git *p,
+ struct min_abbrev_data *mad)
+{
+ int match = 0;
+ uint32_t num, first = 0;
+ struct object_id oid;
+ const struct object_id *mad_oid;
+
+ if (open_pack_index(p) || !p->num_objects)
+ return;
+
+ num = p->num_objects;
+ mad_oid = mad->oid;
+ match = bsearch_pack(mad_oid, p, &first);
+
+ /*
+ * first is now the position in the packfile where we would insert
+ * mad->hash if it does not exist (or the position of mad->hash if
+ * it does exist). Hence, we consider a maximum of two objects
+ * nearby for the abbreviation length.
+ */
+ mad->init_len = 0;
+ if (!match) {
+ if (nth_packed_object_oid(&oid, p, first))
+ extend_abbrev_len(&oid, mad);
+ } else if (first < num - 1) {
+ if (nth_packed_object_oid(&oid, p, first + 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ if (first > 0) {
+ if (nth_packed_object_oid(&oid, p, first - 1))
+ extend_abbrev_len(&oid, mad);
+ }
+ mad->init_len = mad->cur_len;
+}
+
+static void find_abbrev_len_packed(struct min_abbrev_data *mad)
{
- int status, exists;
+ struct packed_git *p;
+
+ for (p = get_packed_git(the_repository); p; p = p->next)
+ find_abbrev_len_for_pack(p, mad);
+}
+int find_unique_abbrev_r(char *hex, const struct object_id *oid, int len)
+{
+ struct disambiguate_state ds;
+ struct min_abbrev_data mad;
+ struct object_id oid_ret;
if (len < 0) {
unsigned long count = approximate_object_count();
/*
len = FALLBACK_DEFAULT_ABBREV;
}
- sha1_to_hex_r(hex, sha1);
+ oid_to_hex_r(hex, oid);
if (len == GIT_SHA1_HEXSZ || !len)
return GIT_SHA1_HEXSZ;
- exists = has_sha1_file(sha1);
- while (len < GIT_SHA1_HEXSZ) {
- struct object_id oid_ret;
- status = get_short_oid(hex, len, &oid_ret, GET_OID_QUIETLY);
- if (exists
- ? !status
- : status == SHORT_NAME_NOT_FOUND) {
- hex[len] = 0;
- return len;
- }
- len++;
- }
- return len;
+
+ mad.init_len = len;
+ mad.cur_len = len;
+ mad.hex = hex;
+ mad.oid = oid;
+
+ find_abbrev_len_packed(&mad);
+
+ if (init_object_disambiguation(hex, mad.cur_len, &ds) < 0)
+ return -1;
+
+ ds.fn = extend_abbrev_len;
+ ds.always_call_fn = 1;
+ ds.cb_data = (void *)&mad;
+
+ find_short_object_filename(&ds);
+ (void)finish_object_disambiguation(&ds, &oid_ret);
+
+ hex[mad.cur_len] = 0;
+ return mad.cur_len;
}
-const char *find_unique_abbrev(const unsigned char *sha1, int len)
+const char *find_unique_abbrev(const struct object_id *oid, int len)
{
static int bufno;
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);
+ find_unique_abbrev_r(hex, oid, len);
return hex;
}
if (len == GIT_SHA1_HEXSZ && !get_oid_hex(str, oid)) {
if (warn_ambiguous_refs && warn_on_object_refname_ambiguity) {
- refs_found = dwim_ref(str, len, tmp_oid.hash, &real_ref);
+ refs_found = dwim_ref(str, len, &tmp_oid, &real_ref);
if (refs_found > 0) {
warning(warn_msg, len, str);
if (advice_object_name_warning)
if (!len && reflog_len)
/* allow "@{...}" to mean the current branch reflog */
- refs_found = dwim_ref("HEAD", 4, oid->hash, &real_ref);
+ refs_found = dwim_ref("HEAD", 4, oid, &real_ref);
else if (reflog_len)
- refs_found = dwim_log(str, len, oid->hash, &real_ref);
+ refs_found = dwim_log(str, len, oid, &real_ref);
else
- refs_found = dwim_ref(str, len, oid->hash, &real_ref);
+ refs_found = dwim_ref(str, len, oid, &real_ref);
if (!refs_found)
return -1;
return -1;
}
}
- if (read_ref_at(real_ref, flags, at_time, nth, oid->hash, NULL,
+ if (read_ref_at(real_ref, flags, at_time, nth, oid, NULL,
&co_time, &co_tz, &co_cnt)) {
if (!len) {
if (starts_with(real_ref, "refs/heads/")) {
if (name)
error("%.*s: expected %s type, but the object "
"dereferences to %s type",
- namelen, name, typename(expected_type),
- typename(o->type));
+ namelen, name, type_name(expected_type),
+ type_name(o->type));
return NULL;
}
}
strbuf_branchname(sb, name, INTERPRET_BRANCH_LOCAL);
else
strbuf_addstr(sb, name);
- if (name[0] == '-')
- return -1;
+
+ /*
+ * This splice must be done even if we end up rejecting the
+ * name; builtin/branch.c::copy_or_rename_branch() still wants
+ * to see what the name expanded to so that "branch -m" can be
+ * used as a tool to correct earlier mistakes.
+ */
strbuf_splice(sb, 0, 0, "refs/heads/", 11);
+
+ if (*name == '-' ||
+ !strcmp(sb->buf, "refs/heads/HEAD"))
+ return -1;
+
return check_refname_format(sb->buf, 0);
}
if (is_missing_file_error(errno)) {
char *fullname = xstrfmt("%s%s", prefix, filename);
- if (!get_tree_entry(tree_oid->hash, fullname,
- oid.hash, &mode)) {
+ if (!get_tree_entry(tree_oid, fullname, &oid, &mode)) {
die("Path '%s' exists, but not '%s'.\n"
"Did you mean '%.*s:%s' aka '%.*s:./%s'?",
fullname,
if (new_filename)
filename = new_filename;
if (flags & GET_OID_FOLLOW_SYMLINKS) {
- ret = get_tree_entry_follow_symlinks(tree_oid.hash,
- filename, oid->hash, &oc->symlink_path,
+ ret = get_tree_entry_follow_symlinks(&tree_oid,
+ filename, oid, &oc->symlink_path,
&oc->mode);
} else {
- ret = get_tree_entry(tree_oid.hash, filename,
- oid->hash, &oc->mode);
+ ret = get_tree_entry(&tree_oid, filename, oid,
+ &oc->mode);
if (ret && only_to_die) {
diagnose_invalid_oid_path(prefix,
filename,
name, len);
}
}
- hashcpy(oc->tree, tree_oid.hash);
if (flags & GET_OID_RECORD_PATH)
oc->path = xstrdup(filename);