From: Junio C Hamano Date: Mon, 3 Aug 2015 18:01:10 +0000 (-0700) Subject: Merge branch 'mh/replace-refs' X-Git-Tag: v2.6.0-rc0~117 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/31a0ad545681159be2ccc633a1a16a891cafbae3?hp=-c Merge branch 'mh/replace-refs' Add an environment variable to tell Git to look into refs hierarchy other than refs/replace/ for the object replacement data. * mh/replace-refs: Allow to control where the replace refs are looked for --- 31a0ad545681159be2ccc633a1a16a891cafbae3 diff --combined builtin/replace.c index 0d52e7fa1d,b5b7139645..6b3c469a33 --- a/builtin/replace.c +++ b/builtin/replace.c @@@ -35,7 -35,7 +35,7 @@@ struct show_data enum replace_format format; }; -static int show_reference(const char *refname, const unsigned char *sha1, +static int show_reference(const char *refname, const struct object_id *oid, int flag, void *cb_data) { struct show_data *data = cb_data; @@@ -44,19 -44,19 +44,19 @@@ if (data->format == REPLACE_FORMAT_SHORT) printf("%s\n", refname); else if (data->format == REPLACE_FORMAT_MEDIUM) - printf("%s -> %s\n", refname, sha1_to_hex(sha1)); + printf("%s -> %s\n", refname, oid_to_hex(oid)); else { /* data->format == REPLACE_FORMAT_LONG */ - unsigned char object[20]; + struct object_id object; enum object_type obj_type, repl_type; - if (get_sha1(refname, object)) + if (get_sha1(refname, object.hash)) return error("Failed to resolve '%s' as a valid ref.", refname); - obj_type = sha1_object_info(object, NULL); - repl_type = sha1_object_info(sha1, NULL); + obj_type = sha1_object_info(object.hash, NULL); + repl_type = sha1_object_info(oid->hash, NULL); printf("%s (%s) -> %s (%s)\n", refname, typename(obj_type), - sha1_to_hex(sha1), typename(repl_type)); + oid_to_hex(oid), typename(repl_type)); } } @@@ -82,7 -82,7 +82,7 @@@ static int list_replace_refs(const cha "valid formats are 'short', 'medium' and 'long'\n", format); - for_each_replace_ref(show_reference, (void *) &data); + for_each_replace_ref(show_reference, (void *)&data); return 0; } @@@ -104,9 -104,9 +104,9 @@@ static int for_each_replace_name(const continue; } full_hex = sha1_to_hex(sha1); - snprintf(ref, sizeof(ref), "refs/replace/%s", full_hex); + snprintf(ref, sizeof(ref), "%s%s", git_replace_ref_base, full_hex); /* read_ref() may reuse the buffer */ - full_hex = ref + strlen("refs/replace/"); + full_hex = ref + strlen(git_replace_ref_base); if (read_ref(ref, sha1)) { error("replace ref '%s' not found.", full_hex); had_error = 1; @@@ -134,7 -134,7 +134,7 @@@ static void check_ref_valid(unsigned ch int force) { if (snprintf(ref, ref_size, - "refs/replace/%s", + "%s%s", git_replace_ref_base, sha1_to_hex(object)) > ref_size - 1) die("replace ref name too long: %.*s...", 50, ref); if (check_refname_format(ref, 0)) diff --combined cache.h index 4f554664c5,83b902befb..8b621d7352 --- a/cache.h +++ b/cache.h @@@ -397,6 -397,7 +397,7 @@@ static inline enum object_type object_t #define EXEC_PATH_ENVIRONMENT "GIT_EXEC_PATH" #define CEILING_DIRECTORIES_ENVIRONMENT "GIT_CEILING_DIRECTORIES" #define NO_REPLACE_OBJECTS_ENVIRONMENT "GIT_NO_REPLACE_OBJECTS" + #define GIT_REPLACE_REF_BASE_ENVIRONMENT "GIT_REPLACE_REF_BASE" #define GITATTRIBUTES_FILE ".gitattributes" #define INFOATTRIBUTES_FILE "info/attributes" #define ATTRIBUTE_MACRO_PREFIX "[attr]" @@@ -622,6 -623,7 +623,7 @@@ extern unsigned long pack_size_limit_cf * been sought but there were none. */ extern int check_replace_refs; + extern char *git_replace_ref_base; extern int fsync_object_files; extern int core_preload_index; @@@ -943,17 -945,8 +945,17 @@@ extern int has_sha1_pack(const unsigne * Return true iff we have an object named sha1, whether local or in * an alternate object database, and whether packed or loose. This * function does not respect replace references. + * + * If the QUICK flag is set, do not re-check the pack directory + * when we cannot find the object (this means we may give a false + * negative answer if another process is simultaneously repacking). */ -extern int has_sha1_file(const unsigned char *sha1); +#define HAS_SHA1_QUICK 0x1 +extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags); +static inline int has_sha1_file(const unsigned char *sha1) +{ + return has_sha1_file_with_flags(sha1, 0); +} /* * Return true iff an alternate object database has a loose object @@@ -1707,6 -1700,5 +1709,6 @@@ int stat_validity_check(struct stat_val void stat_validity_update(struct stat_validity *sv, int fd); int versioncmp(const char *s1, const char *s2); +void sleep_millisec(int millisec); #endif /* CACHE_H */ diff --combined log-tree.c index 01beb11f65,9c25bbc1c5..e2f6de73ef --- a/log-tree.c +++ b/log-tree.c @@@ -89,29 -89,29 +89,30 @@@ const struct name_decoration *get_name_ return lookup_decoration(&name_decoration, obj); } -static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) +static int add_ref_decoration(const char *refname, const struct object_id *oid, + int flags, void *cb_data) { struct object *obj; enum decoration_type type = DECORATION_NONE; assert(cb_data == NULL); - if (starts_with(refname, "refs/replace/")) { + if (starts_with(refname, git_replace_ref_base)) { - unsigned char original_sha1[20]; + struct object_id original_oid; if (!check_replace_refs) return 0; - if (get_oid_hex(refname + 13, &original_oid)) { - if (get_sha1_hex(refname + strlen(git_replace_ref_base), - original_sha1)) { ++ if (get_oid_hex(refname + strlen(git_replace_ref_base), ++ &original_oid)) { warning("invalid replace ref %s", refname); return 0; } - obj = parse_object(original_sha1); + obj = parse_object(original_oid.hash); if (obj) add_name_decoration(DECORATION_GRAFTED, "replaced", obj); return 0; } - obj = parse_object(sha1); + obj = parse_object(oid->hash); if (!obj) return 0; @@@ -150,7 -150,6 +151,7 @@@ static int add_graft_decoration(const s void load_ref_decorations(int flags) { if (!decoration_loaded) { + decoration_loaded = 1; decoration_flags = flags; for_each_ref(add_ref_decoration, NULL); diff --combined refs.c index 7ac05cf21a,6fc65d239f..227cb50c44 --- a/refs.c +++ b/refs.c @@@ -10,7 -10,7 +10,7 @@@ struct ref_lock char *ref_name; char *orig_ref_name; struct lock_file *lk; - unsigned char old_sha1[20]; + struct object_id old_oid; }; /* @@@ -161,7 -161,7 +161,7 @@@ struct ref_value * null. If REF_ISSYMREF, then this is the name of the object * referred to by the last reference in the symlink chain. */ - unsigned char sha1[20]; + struct object_id oid; /* * If REF_KNOWS_PEELED, then this field holds the peeled value @@@ -169,7 -169,7 +169,7 @@@ * be peelable. See the documentation for peel_ref() for an * exact definition of "peelable". */ - unsigned char peeled[20]; + struct object_id peeled; }; struct ref_cache; @@@ -351,8 -351,8 +351,8 @@@ static struct ref_entry *create_ref_ent die("Reference has invalid format: '%s'", refname); len = strlen(refname) + 1; ref = xmalloc(sizeof(struct ref_entry) + len); - hashcpy(ref->u.value.sha1, sha1); - hashclr(ref->u.value.peeled); + hashcpy(ref->u.value.oid.hash, sha1); + oidclr(&ref->u.value.peeled); memcpy(ref->name, refname, len); ref->flag = flag; return ref; @@@ -626,7 -626,7 +626,7 @@@ static int is_dup_ref(const struct ref_ /* This is impossible by construction */ die("Reference directory conflict: %s", ref1->name); - if (hashcmp(ref1->u.value.sha1, ref2->u.value.sha1)) + if (oidcmp(&ref1->u.value.oid, &ref2->u.value.oid)) die("Duplicated ref, and SHA1s don't match: %s", ref1->name); warning("Duplicated ref: %s", ref1->name); @@@ -674,7 -674,7 +674,7 @@@ static int ref_resolves_to_object(struc { if (entry->flag & REF_ISBROKEN) return 0; - if (!has_sha1_file(entry->u.value.sha1)) { + if (!has_sha1_file(entry->u.value.oid.hash)) { error("%s does not point to a valid object!", entry->name); return 0; } @@@ -722,7 -722,7 +722,7 @@@ static int do_one_ref(struct ref_entry /* Store the old value, in case this is a recursive call: */ old_current_ref = current_ref; current_ref = entry; - retval = data->fn(entry->name + data->trim, entry->u.value.sha1, + retval = data->fn(entry->name + data->trim, &entry->u.value.oid, entry->flag, data->cb_data); current_ref = old_current_ref; return retval; @@@ -1258,7 -1258,7 +1258,7 @@@ static void read_packed_refs(FILE *f, s line.len == PEELED_LINE_LENGTH && line.buf[PEELED_LINE_LENGTH - 1] == '\n' && !get_sha1_hex(line.buf + 1, sha1)) { - hashcpy(last->u.value.peeled, sha1); + hashcpy(last->u.value.peeled.hash, sha1); /* * Regardless of what the file header said, * we definitely know the value of *this* @@@ -1373,34 -1373,19 +1373,34 @@@ static void read_loose_refs(const char create_dir_entry(refs, refname.buf, refname.len, 1)); } else { + int read_ok; + if (*refs->name) { hashclr(sha1); flag = 0; - if (resolve_gitlink_ref(refs->name, refname.buf, sha1) < 0) { - hashclr(sha1); - flag |= REF_ISBROKEN; - } - } else if (read_ref_full(refname.buf, - RESOLVE_REF_READING, - sha1, &flag)) { + read_ok = !resolve_gitlink_ref(refs->name, + refname.buf, sha1); + } else { + read_ok = !read_ref_full(refname.buf, + RESOLVE_REF_READING, + sha1, &flag); + } + + if (!read_ok) { hashclr(sha1); flag |= REF_ISBROKEN; + } else if (is_null_sha1(sha1)) { + /* + * It is so astronomically unlikely + * that NULL_SHA1 is the SHA-1 of an + * actual object that we consider its + * appearance in a loose reference + * file to be repo corruption + * (probably due to a software bug). + */ + flag |= REF_ISBROKEN; } + if (check_refname_format(refname.buf, REFNAME_ALLOW_ONELEVEL)) { if (!refname_is_safe(refname.buf)) @@@ -1454,7 -1439,7 +1454,7 @@@ static int resolve_gitlink_packed_ref(s if (ref == NULL) return -1; - hashcpy(sha1, ref->u.value.sha1); + hashcpy(sha1, ref->u.value.oid.hash); return 0; } @@@ -1541,7 -1526,7 +1541,7 @@@ static int resolve_missing_loose_ref(co */ entry = get_packed_ref(refname); if (entry) { - hashcpy(sha1, entry->u.value.sha1); + hashcpy(sha1, entry->u.value.oid.hash); if (flags) *flags |= REF_ISPACKED; return 0; @@@ -1771,14 -1756,13 +1771,14 @@@ int ref_exists(const char *refname return !!resolve_ref_unsafe(refname, RESOLVE_REF_READING, sha1, NULL); } -static int filter_refs(const char *refname, const unsigned char *sha1, int flags, - void *data) +static int filter_refs(const char *refname, const struct object_id *oid, + int flags, void *data) { struct ref_filter *filter = (struct ref_filter *)data; + if (wildmatch(filter->pattern, refname, 0, NULL)) return 0; - return filter->fn(refname, sha1, flags, filter->cb_data); + return filter->fn(refname, oid, flags, filter->cb_data); } enum peel_status { @@@ -1852,9 -1836,9 +1852,9 @@@ static enum peel_status peel_entry(stru if (entry->flag & REF_KNOWS_PEELED) { if (repeel) { entry->flag &= ~REF_KNOWS_PEELED; - hashclr(entry->u.value.peeled); + oidclr(&entry->u.value.peeled); } else { - return is_null_sha1(entry->u.value.peeled) ? + return is_null_oid(&entry->u.value.peeled) ? PEEL_NON_TAG : PEEL_PEELED; } } @@@ -1863,7 -1847,7 +1863,7 @@@ if (entry->flag & REF_ISSYMREF) return PEEL_IS_SYMREF; - status = peel_object(entry->u.value.sha1, entry->u.value.peeled); + status = peel_object(entry->u.value.oid.hash, entry->u.value.peeled.hash); if (status == PEEL_PEELED || status == PEEL_NON_TAG) entry->flag |= REF_KNOWS_PEELED; return status; @@@ -1878,7 -1862,7 +1878,7 @@@ int peel_ref(const char *refname, unsig || !strcmp(current_ref->name, refname))) { if (peel_entry(current_ref, 0)) return -1; - hashcpy(sha1, current_ref->u.value.peeled); + hashcpy(sha1, current_ref->u.value.peeled.hash); return 0; } @@@ -1898,7 -1882,7 +1898,7 @@@ if (r) { if (peel_entry(r, 0)) return -1; - hashcpy(sha1, r->u.value.peeled); + hashcpy(sha1, r->u.value.peeled.hash); return 0; } } @@@ -1913,17 -1897,17 +1913,17 @@@ struct warn_if_dangling_data const char *msg_fmt; }; -static int warn_if_dangling_symref(const char *refname, const unsigned char *sha1, +static int warn_if_dangling_symref(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct warn_if_dangling_data *d = cb_data; const char *resolves_to; - unsigned char junk[20]; + struct object_id junk; if (!(flags & REF_ISSYMREF)) return 0; - resolves_to = resolve_ref_unsafe(refname, 0, junk, NULL); + resolves_to = resolve_ref_unsafe(refname, 0, junk.hash, NULL); if (!resolves_to || (d->refname ? strcmp(resolves_to, d->refname) @@@ -2043,18 -2027,18 +2043,18 @@@ static int do_for_each_ref(struct ref_c static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data) { - unsigned char sha1[20]; + struct object_id oid; int flag; if (submodule) { - if (resolve_gitlink_ref(submodule, "HEAD", sha1) == 0) - return fn("HEAD", sha1, 0, cb_data); + if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0) + return fn("HEAD", &oid, 0, cb_data); return 0; } - if (!read_ref_full("HEAD", RESOLVE_REF_READING, sha1, &flag)) - return fn("HEAD", sha1, flag, cb_data); + if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag)) + return fn("HEAD", &oid, flag, cb_data); return 0; } @@@ -2122,19 -2106,20 +2122,20 @@@ int for_each_remote_ref_submodule(cons int for_each_replace_ref(each_ref_fn fn, void *cb_data) { - return do_for_each_ref(&ref_cache, "refs/replace/", fn, 13, 0, cb_data); + return do_for_each_ref(&ref_cache, git_replace_ref_base, fn, + strlen(git_replace_ref_base), 0, cb_data); } int head_ref_namespaced(each_ref_fn fn, void *cb_data) { struct strbuf buf = STRBUF_INIT; int ret = 0; - unsigned char sha1[20]; + struct object_id oid; int flag; strbuf_addf(&buf, "%sHEAD", get_git_namespace()); - if (!read_ref_full(buf.buf, RESOLVE_REF_READING, sha1, &flag)) - ret = fn(buf.buf, sha1, flag, cb_data); + if (!read_ref_full(buf.buf, RESOLVE_REF_READING, oid.hash, &flag)) + ret = fn(buf.buf, &oid, flag, cb_data); strbuf_release(&buf); return ret; @@@ -2234,35 -2219,27 +2235,35 @@@ static void unlock_ref(struct ref_lock free(lock); } -/* This function should make sure errno is meaningful on error */ -static struct ref_lock *verify_lock(struct ref_lock *lock, - const unsigned char *old_sha1, int mustexist) +/* + * Verify that the reference locked by lock has the value old_sha1. + * Fail if the reference doesn't exist and mustexist is set. Return 0 + * on success. On error, write an error message to err, set errno, and + * return a negative value. + */ +static int verify_lock(struct ref_lock *lock, + const unsigned char *old_sha1, int mustexist, + struct strbuf *err) { + assert(err); + if (read_ref_full(lock->ref_name, mustexist ? RESOLVE_REF_READING : 0, - lock->old_sha1, NULL)) { + lock->old_oid.hash, NULL)) { int save_errno = errno; - error("Can't verify ref %s", lock->ref_name); - unlock_ref(lock); + strbuf_addf(err, "can't verify ref %s", lock->ref_name); errno = save_errno; - return NULL; + return -1; } - if (hashcmp(lock->old_sha1, old_sha1)) { - error("Ref %s is at %s but expected %s", lock->ref_name, - sha1_to_hex(lock->old_sha1), sha1_to_hex(old_sha1)); - unlock_ref(lock); + if (hashcmp(lock->old_oid.hash, old_sha1)) { + strbuf_addf(err, "ref %s is at %s but expected %s", + lock->ref_name, + sha1_to_hex(lock->old_oid.hash), + sha1_to_hex(old_sha1)); errno = EBUSY; - return NULL; + return -1; } - return lock; + return 0; } static int remove_empty_directories(const char *file) @@@ -2405,7 -2382,7 +2406,7 @@@ static struct ref_lock *lock_ref_sha1_b } refname = resolve_ref_unsafe(refname, resolve_flags, - lock->old_sha1, &type); + lock->old_oid.hash, &type); if (!refname && errno == EISDIR) { /* we are trying to lock foo but we used to * have foo/bar which now does not exist; @@@ -2424,7 -2401,7 +2425,7 @@@ goto error_return; } refname = resolve_ref_unsafe(orig_refname, resolve_flags, - lock->old_sha1, &type); + lock->old_oid.hash, &type); } if (type_p) *type_p = type; @@@ -2444,7 -2421,7 +2445,7 @@@ * refname, nor a packed ref whose name is a proper prefix of * our refname. */ - if (is_null_sha1(lock->old_sha1) && + if (is_null_oid(&lock->old_oid) && verify_refname_available(refname, extras, skip, get_packed_refs(&ref_cache), err)) { last_errno = ENOTDIR; @@@ -2490,11 -2467,7 +2491,11 @@@ goto error_return; } } - return old_sha1 ? verify_lock(lock, old_sha1, mustexist) : lock; + if (old_sha1 && verify_lock(lock, old_sha1, mustexist, err)) { + last_errno = errno; + goto error_return; + } + return lock; error_return: unlock_ref(lock); @@@ -2524,9 -2497,9 +2525,9 @@@ static int write_packed_entry_fn(struc if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG) error("internal error: %s is not a valid packed reference!", entry->name); - write_packed_entry(cb_data, entry->name, entry->u.value.sha1, + write_packed_entry(cb_data, entry->name, entry->u.value.oid.hash, peel_status == PEEL_PEELED ? - entry->u.value.peeled : NULL); + entry->u.value.peeled.hash : NULL); return 0; } @@@ -2643,24 -2616,24 +2644,24 @@@ static int pack_if_possible_fn(struct r peel_status = peel_entry(entry, 1); if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG) die("internal error peeling reference %s (%s)", - entry->name, sha1_to_hex(entry->u.value.sha1)); + entry->name, oid_to_hex(&entry->u.value.oid)); packed_entry = find_ref(cb->packed_refs, entry->name); if (packed_entry) { /* Overwrite existing packed entry with info from loose entry */ packed_entry->flag = REF_ISPACKED | REF_KNOWS_PEELED; - hashcpy(packed_entry->u.value.sha1, entry->u.value.sha1); + oidcpy(&packed_entry->u.value.oid, &entry->u.value.oid); } else { - packed_entry = create_ref_entry(entry->name, entry->u.value.sha1, + packed_entry = create_ref_entry(entry->name, entry->u.value.oid.hash, REF_ISPACKED | REF_KNOWS_PEELED, 0); add_ref(cb->packed_refs, packed_entry); } - hashcpy(packed_entry->u.value.peeled, entry->u.value.peeled); + oidcpy(&packed_entry->u.value.peeled, &entry->u.value.peeled); /* Schedule the loose reference for pruning if requested. */ if ((cb->flags & PACK_REFS_PRUNE)) { int namelen = strlen(entry->name) + 1; struct ref_to_prune *n = xcalloc(1, sizeof(*n) + namelen); - hashcpy(n->sha1, entry->u.value.sha1); + hashcpy(n->sha1, entry->u.value.oid.hash); strcpy(n->name, entry->name); n->next = cb->ref_to_prune; cb->ref_to_prune = n; @@@ -2971,7 -2944,7 +2972,7 @@@ int rename_ref(const char *oldrefname, strbuf_release(&err); goto rollback; } - hashcpy(lock->old_sha1, orig_sha1); + hashcpy(lock->old_oid.hash, orig_sha1); if (write_ref_to_lockfile(lock, orig_sha1) || commit_ref_update(lock, orig_sha1, logmsg)) { @@@ -3226,9 -3199,9 +3227,9 @@@ static int commit_ref_update(struct ref const unsigned char *sha1, const char *logmsg) { clear_loose_ref_cache(&ref_cache); - if (log_ref_write(lock->ref_name, lock->old_sha1, sha1, logmsg) < 0 || + if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg) < 0 || (strcmp(lock->ref_name, lock->orig_ref_name) && - log_ref_write(lock->orig_ref_name, lock->old_sha1, sha1, logmsg) < 0)) { + log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg) < 0)) { unlock_ref(lock); return -1; } @@@ -3252,7 -3225,7 +3253,7 @@@ head_sha1, &head_flag); if (head_ref && (head_flag & REF_ISSYMREF) && !strcmp(head_ref, lock->ref_name)) - log_ref_write("HEAD", lock->old_sha1, sha1, logmsg); + log_ref_write("HEAD", lock->old_oid.hash, sha1, logmsg); } if (commit_ref(lock)) { error("Couldn't set %s", lock->ref_name); @@@ -3644,12 -3617,11 +3645,12 @@@ static int do_for_each_reflog(struct st strbuf_addch(name, '/'); retval = do_for_each_reflog(name, fn, cb_data); } else { - unsigned char sha1[20]; - if (read_ref_full(name->buf, 0, sha1, NULL)) + struct object_id oid; + + if (read_ref_full(name->buf, 0, oid.hash, NULL)) retval = error("bad ref for %s", name->buf); else - retval = fn(name->buf, sha1, 0, cb_data); + retval = fn(name->buf, &oid, 0, cb_data); } if (retval) break; @@@ -3939,7 -3911,7 +3940,7 @@@ int ref_transaction_commit(struct ref_t ? TRANSACTION_NAME_CONFLICT : TRANSACTION_GENERIC_ERROR; reason = strbuf_detach(err, NULL); - strbuf_addf(err, "Cannot lock ref '%s': %s", + strbuf_addf(err, "cannot lock ref '%s': %s", update->refname, reason); free(reason); goto cleanup; @@@ -3950,7 -3922,7 +3951,7 @@@ (update->flags & REF_NODEREF)); if (!overwriting_symref && - !hashcmp(update->lock->old_sha1, update->new_sha1)) { + !hashcmp(update->lock->old_oid.hash, update->new_sha1)) { /* * The reference already has the desired * value, so we don't need to write it. @@@ -3962,7 -3934,7 +3963,7 @@@ * write_ref_to_lockfile(): */ update->lock = NULL; - strbuf_addf(err, "Cannot update the ref '%s'.", + strbuf_addf(err, "cannot update the ref '%s'.", update->refname); ret = TRANSACTION_GENERIC_ERROR; goto cleanup;