summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2020-06-30 08:53:59 +0200
committerPatrick Steinhardt <ps@pks.im>2020-07-12 15:25:10 +0200
commit1f39593b141005b0c8035852d891fa01ead7bd78 (patch)
treef90ded22f5f6f30bc3b0c32dcafc93e3478407f2
parente02478b19b1084775c0aa1f7c658958810d29752 (diff)
downloadlibgit2-1f39593b141005b0c8035852d891fa01ead7bd78.tar.gz
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.
-rw-r--r--src/refdb.c49
-rw-r--r--src/refdb.h16
-rw-r--r--src/refdb_fs.c52
3 files changed, 78 insertions, 39 deletions
diff --git a/src/refdb.c b/src/refdb.c
index 19b9887f5..764d2c1f7 100644
--- a/src/refdb.c
+++ b/src/refdb.c
@@ -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);
diff --git a/src/refdb.h b/src/refdb.h
index 7578f66e1..05c0e1c67 100644
--- a/src/refdb.h
+++ b/src/refdb.h
@@ -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);
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index eeddac324..7e0481909 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -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;
}