diff options
author | Patrick Steinhardt <ps@pks.im> | 2020-06-30 08:53:59 +0200 |
---|---|---|
committer | Patrick Steinhardt <ps@pks.im> | 2020-07-12 15:25:10 +0200 |
commit | 1f39593b141005b0c8035852d891fa01ead7bd78 (patch) | |
tree | f90ded22f5f6f30bc3b0c32dcafc93e3478407f2 | |
parent | e02478b19b1084775c0aa1f7c658958810d29752 (diff) | |
download | libgit2-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.c | 49 | ||||
-rw-r--r-- | src/refdb.h | 16 | ||||
-rw-r--r-- | src/refdb_fs.c | 52 |
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; } |