Commit 1f39593b by Patrick Steinhardt

refdb: extract function to check whether to append HEAD to the reflog

The logic to determine whether a reflog entry should be for the HEAD
reference is non-trivial. Currently, the only user of this is the
filesystem-based refdb, but with the advent of the reftable refdb we're
going to add a second user that's interested in having the same
behaviour.

Let's pull out a new function that checks whether a given reference
should cause a entry to be written to the HEAD reflog as a preparatory
step.
parent e02478b1
......@@ -268,6 +268,55 @@ int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *
return 0;
}
int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref)
{
git_reference *head = NULL, *peeled = NULL;
const char *name;
int error;
*out = 0;
if (ref->type == GIT_REFERENCE_SYMBOLIC) {
error = 0;
goto out;
}
if ((error = git_refdb_lookup(&head, db, GIT_HEAD_FILE)) < 0)
goto out;
if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
goto out;
/* Go down the symref chain until we find the branch */
while (git_reference_type(head) == GIT_REFERENCE_SYMBOLIC) {
if ((error = git_refdb_lookup(&peeled, db, git_reference_symbolic_target(head))) < 0)
break;
git_reference_free(head);
head = peeled;
peeled = NULL;
}
if (error < 0) {
if (error != GIT_ENOTFOUND)
goto out;
error = 0;
name = git_reference_symbolic_target(head);
} else {
name = git_reference_name(head);
}
if (strcmp(name, ref->name))
goto out;
*out = 1;
out:
git_reference_free(peeled);
git_reference_free(head);
return error;
}
int git_refdb_has_log(git_refdb *db, const char *refname)
{
assert(db && refname);
......
......@@ -78,6 +78,22 @@ int git_refdb_reflog_write(git_reflog *reflog);
*/
int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference *ref);
/**
* Determine whether a reflog entry should be created for HEAD if creating one
* for the given reference
*
* In case the given reference is being pointed to by HEAD, then creating a
* reflog entry for this reference also requires us to create a corresponding
* reflog entry for HEAD. This function can be used to determine that scenario.
*
* @param out pointer to which the result will be written, `1` means a reflog
* entry should be written, `0` means none should be written.
* @param db The refdb to decide this for.
* @param ref The reference one wants to check.
* @return `0` on success, a negative error code otherwise.
*/
int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_reference *ref);
int git_refdb_has_log(git_refdb *db, const char *refname);
int git_refdb_ensure_log(git_refdb *refdb, const char *refname);
......
......@@ -1181,54 +1181,28 @@ out:
*/
static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref, const git_signature *who, const char *message)
{
int error;
git_reference *head = NULL;
git_refdb *refdb = NULL;
int error, write_reflog;
git_oid old_id;
git_reference *tmp = NULL, *head = NULL, *peeled = NULL;
const char *name;
if (ref->type == GIT_REFERENCE_SYMBOLIC)
return 0;
if ((error = git_repository_refdb(&refdb, backend->repo)) < 0 ||
(error = git_refdb_should_write_head_reflog(&write_reflog, refdb, ref)) < 0)
goto out;
if (!write_reflog)
goto out;
/* if we can't resolve, we use {0}*40 as old id */
if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0)
memset(&old_id, 0, sizeof(old_id));
if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0)
return error;
if (git_reference_type(head) == GIT_REFERENCE_DIRECT)
goto cleanup;
if ((error = git_reference_lookup(&tmp, backend->repo, GIT_HEAD_FILE)) < 0)
goto cleanup;
/* Go down the symref chain until we find the branch */
while (git_reference_type(tmp) == GIT_REFERENCE_SYMBOLIC) {
error = git_reference_lookup(&peeled, backend->repo, git_reference_symbolic_target(tmp));
if (error < 0)
break;
git_reference_free(tmp);
tmp = peeled;
}
if (error == GIT_ENOTFOUND) {
error = 0;
name = git_reference_symbolic_target(tmp);
} else if (error < 0) {
goto cleanup;
} else {
name = git_reference_name(tmp);
}
if (strcmp(name, ref->name))
goto cleanup;
error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message);
if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0 ||
(error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message)) < 0)
goto out;
cleanup:
git_reference_free(tmp);
out:
git_reference_free(head);
git_refdb_free(refdb);
return error;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment