refs: Introduce git_reference_symbolic_set_target_with_log()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 172fdd2..2dc1376 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -319,6 +319,31 @@ GIT_EXTERN(int) git_reference_symbolic_set_target(
/**
* Create a new reference with the same name as the given reference but a
+ * different symbolic target and update the reflog with a given message.
+ *
+ * The reference must be a symbolic reference, otherwise this will fail.
+ *
+ * The new reference will be written to disk, overwriting the given reference.
+ *
+ * The target name will be checked for validity.
+ * See `git_reference_create_symbolic()` for rules about valid names.
+ *
+ * @param out Pointer to the newly created reference
+ * @param ref The reference
+ * @param target The new target for the reference
+ * @param signature The identity that will used to populate the reflog entry
+ * @param log_message The one line long message that has to be appended
+ * @return 0 on success, EINVALIDSPEC or an error code
+ */
+GIT_EXTERN(int) git_reference_symbolic_set_target_with_log(
+ git_reference **out,
+ git_reference *ref,
+ const char *target,
+ const git_signature *signature,
+ const char *log_message);
+
+/**
+ * Create a new reference with the same name as the given reference but a
* different OID target. The reference must be a direct reference, otherwise
* this will fail.
*
diff --git a/src/refs.c b/src/refs.c
index 75a7e1b..eff6b33 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -523,22 +523,49 @@ int git_reference_set_target_with_log(
out, ref->db->repo, ref->name, id, 1, signature, log_message);
}
+static int ensure_is_an_updatable_symbolic_reference(git_reference *ref)
+{
+ if (ref->type == GIT_REF_SYMBOLIC)
+ return 0;
+
+ giterr_set(GITERR_REFERENCE, "Cannot set symbolic target on a direct reference");
+ return -1;
+}
+
int git_reference_symbolic_set_target(
git_reference **out,
git_reference *ref,
const char *target)
{
+ int error;
+
assert(out && ref && target);
- if (ref->type != GIT_REF_SYMBOLIC) {
- giterr_set(GITERR_REFERENCE,
- "Cannot set symbolic target on a direct reference");
- return -1;
- }
+ if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
+ return error;
return git_reference_symbolic_create(out, ref->db->repo, ref->name, target, 1);
}
+int git_reference_symbolic_set_target_with_log(
+ git_reference **out,
+ git_reference *ref,
+ const char *target,
+ const git_signature *signature,
+ const char *log_message)
+{
+ int error;
+
+ assert(out && ref && target);
+ assert(signature && log_message);
+
+ if ((error = ensure_is_an_updatable_symbolic_reference(ref)) < 0)
+ return error;
+
+ return git_reference_symbolic_create_with_log(
+ out, ref->db->repo, ref->name, target, 1, signature, log_message);
+}
+
int git_reference_rename(
git_reference **out,
git_reference *ref,
diff --git a/tests/refs/settargetwithlog.c b/tests/refs/settargetwithlog.c
index 7bdd6d5..e1f73db 100644
--- a/tests/refs/settargetwithlog.c
+++ b/tests/refs/settargetwithlog.c
@@ -53,3 +53,42 @@ void test_refs_settargetwithlog__updating_a_direct_reference_adds_a_reflog_entry
git_reference_free(reference);
git_signature_free(signature);
}
+
+void test_refs_settargetwithlog__updating_a_symbolic_reference_adds_a_reflog_entry(void)
+{
+ git_reference *reference, *reference_out;
+ git_oid id;
+ git_signature *signature;
+ git_reflog *reflog;
+ const git_reflog_entry *entry;
+
+ const char *name = "HEAD";
+ const char *message = "You've been logged, mate!";
+
+ git_oid_fromstr(&id, br2_tip);
+
+ cl_git_pass(git_signature_now(&signature, "foo", "foo@bar"));
+
+ cl_git_pass(git_reference_lookup(&reference, g_repo, name));
+
+ cl_assert_equal_s(
+ "refs/heads/master", git_reference_symbolic_target(reference));
+
+ cl_git_pass(git_reference_symbolic_set_target_with_log(&reference_out,
+ reference, br2_name, signature, message));
+
+ cl_assert_equal_s(
+ br2_name, git_reference_symbolic_target(reference_out));
+
+ cl_git_pass(git_reflog_read(&reflog, reference));
+
+ entry = git_reflog_entry_byindex(reflog, 0);
+ cl_assert(git_oid_streq(&entry->oid_old, master_tip) == 0);
+ cl_assert(git_oid_streq(&entry->oid_cur, br2_tip) == 0);
+ cl_assert_equal_s(message, entry->msg);
+
+ git_reflog_free(reflog);
+ git_reference_free(reference_out);
+ git_reference_free(reference);
+ git_signature_free(signature);
+}