Commit fc4728e3e2a4094b202a63319232f25adbd55fed

Carlos Martín Nieto 2014-01-29T14:07:18

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.

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(