if (peel_entry(entry, 0))
return -1;
- hashcpy(peeled->hash, entry->u.value.peeled.hash);
+ oidcpy(peeled, &entry->u.value.peeled);
return 0;
}
*/
struct files_ref_store {
struct ref_store base;
+
+ /*
+ * The name of the submodule represented by this object, or
+ * NULL if it represents the main repository's reference
+ * store:
+ */
+ const char *submodule;
+
struct ref_entry *loose;
struct packed_ref_cache *packed;
};
struct files_ref_store *refs = xcalloc(1, sizeof(*refs));
struct ref_store *ref_store = (struct ref_store *)refs;
- base_ref_store_init(ref_store, &refs_be_files, submodule);
+ base_ref_store_init(ref_store, &refs_be_files);
+
+ refs->submodule = xstrdup_or_null(submodule);
return ref_store;
}
+/*
+ * Die if refs is for a submodule (i.e., not for the main repository).
+ * caller is used in any necessary error messages.
+ */
+static void files_assert_main_repository(struct files_ref_store *refs,
+ const char *caller)
+{
+ if (refs->submodule)
+ die("BUG: %s called for a submodule", caller);
+}
+
/*
* Downcast ref_store to files_ref_store. Die if ref_store is not a
* files_ref_store. If submodule_allowed is not true, then also die if
struct ref_store *ref_store, int submodule_allowed,
const char *caller)
{
+ struct files_ref_store *refs;
+
if (ref_store->be != &refs_be_files)
die("BUG: ref_store is type \"%s\" not \"files\" in %s",
ref_store->be->name, caller);
+ refs = (struct files_ref_store *)ref_store;
+
if (!submodule_allowed)
- assert_main_repository(ref_store, caller);
+ files_assert_main_repository(refs, caller);
- return (struct files_ref_store *)ref_store;
+ return refs;
}
/* The length of a peeled reference line in packed-refs, including EOL: */
{
char *packed_refs_file;
- if (*refs->base.submodule)
- packed_refs_file = git_pathdup_submodule(refs->base.submodule,
+ if (refs->submodule)
+ packed_refs_file = git_pathdup_submodule(refs->submodule,
"packed-refs");
else
packed_refs_file = git_pathdup("packed-refs");
size_t path_baselen;
int err = 0;
- if (*refs->base.submodule)
- err = strbuf_git_path_submodule(&path, refs->base.submodule, "%s", dirname);
+ if (refs->submodule)
+ err = strbuf_git_path_submodule(&path, refs->submodule, "%s", dirname);
else
strbuf_git_path(&path, "%s", dirname);
path_baselen = path.len;
create_dir_entry(refs, refname.buf,
refname.len, 1));
} else {
- int read_ok;
-
- if (*refs->base.submodule) {
- hashclr(sha1);
- flag = 0;
- read_ok = !resolve_gitlink_ref(refs->base.submodule,
- refname.buf, sha1);
- } else {
- read_ok = !read_ref_full(refname.buf,
- RESOLVE_REF_READING,
- sha1, &flag);
- }
-
- if (!read_ok) {
+ if (!resolve_ref_recursively(&refs->base,
+ refname.buf,
+ RESOLVE_REF_READING,
+ sha1, &flag)) {
hashclr(sha1);
flag |= REF_ISBROKEN;
} else if (is_null_sha1(sha1)) {
*type = 0;
strbuf_reset(&sb_path);
- if (*refs->base.submodule)
- strbuf_git_path_submodule(&sb_path, refs->base.submodule, "%s", refname);
+ if (refs->submodule)
+ strbuf_git_path_submodule(&sb_path, refs->submodule, "%s", refname);
else
strbuf_git_path(&sb_path, "%s", refname);
int ret = TRANSACTION_GENERIC_ERROR;
assert(err);
- assert_main_repository(&refs->base, "lock_raw_ref");
+ files_assert_main_repository(refs, "lock_raw_ref");
*type = 0;
int resolve_flags = RESOLVE_REF_NO_RECURSE;
int resolved;
- assert_main_repository(&refs->base, "lock_ref_sha1_basic");
+ files_assert_main_repository(refs, "lock_ref_sha1_basic");
assert(err);
lock = xcalloc(1, sizeof(struct ref_lock));
static int timeout_value = 1000;
struct packed_ref_cache *packed_ref_cache;
- assert_main_repository(&refs->base, "lock_packed_refs");
+ files_assert_main_repository(refs, "lock_packed_refs");
if (!timeout_configured) {
git_config_get_int("core.packedrefstimeout", &timeout_value);
int save_errno = 0;
FILE *out;
- assert_main_repository(&refs->base, "commit_packed_refs");
+ files_assert_main_repository(refs, "commit_packed_refs");
if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked");
struct packed_ref_cache *packed_ref_cache =
get_packed_ref_cache(refs);
- assert_main_repository(&refs->base, "rollback_packed_refs");
+ files_assert_main_repository(refs, "rollback_packed_refs");
if (!packed_ref_cache->lock)
die("internal error: packed-refs not locked");
}
ref_transaction_free(transaction);
strbuf_release(&err);
- try_remove_empty_parents(r->name, REMOVE_EMPTY_PARENTS_REF);
}
static void prune_refs(struct ref_to_prune *r)
struct string_list_item *refname;
int ret, needs_repacking = 0, removed = 0;
- assert_main_repository(&refs->base, "repack_without_refs");
+ files_assert_main_repository(refs, "repack_without_refs");
assert(err);
/* Look for a packed ref */
for (i = 0; i < refnames->nr; i++) {
const char *refname = refnames->items[i].string;
- if (delete_ref(refname, NULL, flags))
+ if (delete_ref(NULL, refname, NULL, flags))
result |= error(_("could not remove reference %s"), refname);
}
return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
oldrefname, strerror(errno));
- if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
+ if (delete_ref(logmsg, oldrefname, orig_sha1, REF_NODEREF)) {
error("unable to delete old %s", oldrefname);
goto rollback;
}
*/
if (!read_ref_full(newrefname, RESOLVE_REF_READING | RESOLVE_REF_NO_RECURSE,
sha1, NULL) &&
- delete_ref(newrefname, NULL, REF_NODEREF)) {
+ delete_ref(NULL, newrefname, NULL, REF_NODEREF)) {
if (errno == EISDIR) {
struct strbuf path = STRBUF_INIT;
int result;
}
flag = log_all_ref_updates;
- log_all_ref_updates = 0;
+ log_all_ref_updates = LOG_REFS_NONE;
if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
commit_ref_update(refs, lock, orig_sha1, NULL, &err)) {
error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
{
int logfd, result;
- if (log_all_ref_updates < 0)
- log_all_ref_updates = !is_bare_repository();
+ if (log_all_ref_updates == LOG_REFS_UNSET)
+ log_all_ref_updates = is_bare_repository() ? LOG_REFS_NONE : LOG_REFS_NORMAL;
result = log_ref_setup(refname, flags & REF_FORCE_CREATE_REFLOG,
&logfd, err);
const unsigned char *sha1, const char *logmsg,
struct strbuf *err)
{
- assert_main_repository(&refs->base, "commit_ref_update");
+ files_assert_main_repository(refs, "commit_ref_update");
clear_loose_ref_cache(refs);
if (files_log_ref_write(lock->ref_name, lock->old_oid.hash, sha1,
return ret;
}
-int set_worktree_head_symref(const char *gitdir, const char *target)
+int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg)
{
static struct lock_file head_lock;
struct ref_lock *lock;
lock->lk = &head_lock;
lock->ref_name = xstrdup(head_rel);
- ret = create_symref_locked(lock, head_rel, target, NULL);
+ ret = create_symref_locked(lock, head_rel, target, logmsg);
unlock_ref(lock); /* will free lock */
strbuf_release(&head_path);
int ret;
struct ref_lock *lock;
- assert_main_repository(&refs->base, "lock_ref_for_update");
+ files_assert_main_repository(refs, "lock_ref_for_update");
if ((update->flags & REF_HAVE_NEW) && is_null_sha1(update->new_sha1))
update->flags |= REF_DELETING;
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
+ update->flags |= REF_DELETED_LOOSE;
}
if (!(update->flags & REF_ISPRUNING))
ret = TRANSACTION_GENERIC_ERROR;
goto cleanup;
}
- for_each_string_list_item(ref_to_delete, &refs_to_delete)
- unlink_or_warn(git_path("logs/%s", ref_to_delete->string));
+
+ /* Delete the reflogs of any references that were deleted: */
+ for_each_string_list_item(ref_to_delete, &refs_to_delete) {
+ if (!unlink_or_warn(git_path("logs/%s", ref_to_delete->string)))
+ try_remove_empty_parents(ref_to_delete->string,
+ REMOVE_EMPTY_PARENTS_REFLOG);
+ }
+
clear_loose_ref_cache(refs);
cleanup:
transaction->state = REF_TRANSACTION_CLOSED;
- for (i = 0; i < transaction->nr; i++)
- if (transaction->updates[i]->backend_data)
- unlock_ref(transaction->updates[i]->backend_data);
+ for (i = 0; i < transaction->nr; i++) {
+ struct ref_update *update = transaction->updates[i];
+ struct ref_lock *lock = update->backend_data;
+
+ if (lock)
+ unlock_ref(lock);
+
+ if (update->flags & REF_DELETED_LOOSE) {
+ /*
+ * The loose reference was deleted. Delete any
+ * empty parent directories. (Note that this
+ * can only work because we have already
+ * removed the lockfile.)
+ */
+ try_remove_empty_parents(update->refname,
+ REMOVE_EMPTY_PARENTS_REF);
+ }
+ }
+
string_list_clear(&refs_to_delete, 0);
free(head_ref);
string_list_clear(&affected_refnames, 0);