refs: return GIT_EMODIFIED if the ref target moved In case we loose the race to update the reference, return GIT_EMODIFIED to let the user distinguish it from other types of errors.
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
diff --git a/include/git2/errors.h b/include/git2/errors.h
index 973d560..bcf2f80 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -40,6 +40,7 @@ typedef enum {
GIT_EINVALIDSPEC = -12, /*< Name/ref spec was not in a valid format */
GIT_EMERGECONFLICT = -13, /*< Merge conflicts prevented operation */
GIT_ELOCKED = -14, /*< Lock file prevented operation */
+ GIT_EMODIFIED = -15, /*< Reference value does not match expected */
GIT_PASSTHROUGH = -30, /*< Internal only */
GIT_ITEROVER = -31, /*< Signals end of iteration with iterator */
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 7262294..aab8715 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -182,7 +182,8 @@ GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo,
* @param signature The identity that will used to populate the reflog entry
* @param log_message The one line long message to be appended to the reflog
* @param old_id The old value which the reference should have
- * @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
+ * @return 0 on success, GIT_EMODIFIED if the value of the reference
+ * has changed, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
*/
GIT_EXTERN(int) git_reference_create_matching(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force, const git_signature *signature, const char *log_message, const git_oid *old_id);
@@ -308,7 +309,8 @@ GIT_EXTERN(int) git_reference_symbolic_set_target(
* @param id The new target OID for the reference
* @param signature The identity that will used to populate the reflog entry
* @param log_message The one line long message to be appended to the reflog
- * @return 0 or an error code
+ * @return 0 on success, GIT_EMODIFIED if the value of the reference
+ * has changed, or an error code
*/
GIT_EXTERN(int) git_reference_set_target(
git_reference **out,
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index fd6d61e..0a2a33a 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -941,7 +941,7 @@ static int refdb_fs_backend__write(
refdb_fs_backend *backend = (refdb_fs_backend *)_backend;
git_filebuf file = GIT_FILEBUF_INIT;
git_reference *old_ref;
- int error;
+ int error = 0;
assert(backend);
@@ -961,12 +961,14 @@ static int refdb_fs_backend__write(
if (old_ref->type == GIT_REF_SYMBOLIC) {
giterr_set(GITERR_REFERENCE, "cannot compare id to symbolic reference target");
+ error = -1;
goto on_error;
}
/* Finally we can compare the ids */
if (git_oid_cmp(old_id, &old_ref->target.oid)) {
giterr_set(GITERR_REFERENCE, "old reference value does not match");
+ error = GIT_EMODIFIED;
goto on_error;
}
}
@@ -982,7 +984,7 @@ static int refdb_fs_backend__write(
on_error:
git_filebuf_cleanup(&file);
git_reference_free(old_ref);
- return -1;
+ return error;
}
static int refdb_fs_backend__delete(