Commit e42ea1f488ae50655f31b8f09413a543b0fab9b7

Vicent Martí 2011-11-25T21:30:08

Merge pull request #491 from schu/refs-cleanup reference_rename() cleanup

diff --git a/include/git2/reflog.h b/include/git2/reflog.h
index 9ad42b7..f1d0879 100644
--- a/include/git2/reflog.h
+++ b/include/git2/reflog.h
@@ -51,6 +51,23 @@ GIT_EXTERN(int) git_reflog_read(git_reflog **reflog, git_reference *ref);
 GIT_EXTERN(int) git_reflog_write(git_reference *ref, const git_oid *oid_old, const git_signature *committer, const char *msg);
 
 /**
+ * Rename the reflog for the given reference
+ *
+ * @param ref the reference
+ * @param new_name the new name of the reference
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_reflog_rename(git_reference *ref, const char *new_name);
+
+/**
+ * Delete the reflog for the given reference
+ *
+ * @param ref the reference
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_reflog_delete(git_reference *ref);
+
+/**
  * Get the number of log entries in a reflog
  *
  * @param reflog the previously loaded reflog
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 82c5d88..32671aa 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -183,6 +183,11 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id);
  * If the `force` flag is not enabled, and there's already
  * a reference with the given name, the renaming will fail.
  *
+ * IMPORTANT:
+ * The user needs to write a proper reflog entry if the
+ * reflog is enabled for the repository. We only rename
+ * the reflog if it exists.
+ *
  * @param ref The reference to rename
  * @param new_name The new name for the reference
  * @param force Overwrite an existing reference
diff --git a/src/fileops.h b/src/fileops.h
index 56c4770..e1a59f6 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -90,11 +90,6 @@ extern int git_futils_rmdir_r(const char *path, int force);
 extern int git_futils_mktmp(char *path_out, const char *filename);
 
 /**
- * Atomically rename a file on the filesystem
- */
-extern int git_futils_mv_atomic(const char *from, const char *to);
-
-/**
  * Move a file on the filesystem, create the
  * destination path if it doesn't exist
  */
diff --git a/src/reflog.c b/src/reflog.c
index c136987..fbaaaea 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -255,6 +255,32 @@ int git_reflog_write(git_reference *ref, const git_oid *oid_old,
 	return reflog_write(log_path, old, new, committer, msg);
 }
 
+int git_reflog_rename(git_reference *ref, const char *new_name)
+{
+	char old_path[GIT_PATH_MAX];
+	char new_path[GIT_PATH_MAX];
+
+	git_path_join_n(old_path, 3, ref->owner->path_repository,
+			GIT_REFLOG_DIR, ref->name);
+	git_path_join_n(new_path, 3, ref->owner->path_repository,
+			GIT_REFLOG_DIR, new_name);
+
+	return p_rename(old_path, new_path);
+}
+
+int git_reflog_delete(git_reference *ref)
+{
+	char path[GIT_PATH_MAX];
+
+	git_path_join_n(path, 3, ref->owner->path_repository,
+			GIT_REFLOG_DIR, ref->name);
+
+	if (git_futils_exists(path))
+		return GIT_SUCCESS;
+
+	return p_unlink(path);
+}
+
 unsigned int git_reflog_entrycount(git_reflog *reflog)
 {
 	assert(reflog);
diff --git a/src/refs.c b/src/refs.c
index 5a297a5..2374cc7 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -10,6 +10,7 @@
 #include "repository.h"
 #include "fileops.h"
 #include "pack.h"
+#include "reflog.h"
 
 #include <git2/tag.h>
 #include <git2/object.h>
@@ -1319,28 +1320,6 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
 	}
 
 	/*
-	 * Crude hack: delete any logs till we support proper reflogs.
-	 * Otherwise git.git will possibly fail and leave a mess. git.git
-	 * writes reflogs by default in any repo with a working directory:
-	 *
-	 * "We only enable reflogs in repositories that have a working directory
-	 * associated with them, as shared/bare repositories do not have
-	 * an easy means to prune away old log entries, or may fail logging
-	 * entirely if the user's gecos information is not valid during a push.
-	 * This heuristic was suggested on the mailing list by Junio."
-	 *
-	 * 	Shawn O. Pearce - 0bee59186976b1d9e6b2dd77332480c9480131d5
-	 *
-	 * TODO
-	 *
-	 */
-	git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", ref->name);
-	if (git_futils_isfile(aux_path) == GIT_SUCCESS) {
-		if ((error = p_unlink(aux_path)) < GIT_SUCCESS)
-			goto rollback;
-	}
-
-	/*
 	 * Finally we can create the new reference.
 	 */
 	if (ref->flags & GIT_REF_SYMBOLIC) {
@@ -1352,7 +1331,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
 	}
 
 	if (error < GIT_SUCCESS)
-		goto cleanup;
+		goto rollback;
 
 	/*
 	 * Check if we have to update HEAD.
@@ -1372,6 +1351,14 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force)
 	}
 
 	/*
+	 * Rename the reflog file.
+	 */
+	git_path_join_n(aux_path, 3, ref->owner->path_repository,
+			GIT_REFLOG_DIR, ref->name);
+	if (git_futils_exists(aux_path) == GIT_SUCCESS)
+		error = git_reflog_rename(ref, new_name);
+
+	/*
 	 * Change the name of the reference given by the user.
 	 */
 	git__free(ref->name);
@@ -1398,6 +1385,9 @@ rollback:
 		error = git_reference_create_oid(
 			NULL, ref->owner, ref->name, &ref->target.oid, 0);
 
+	/* The reference is no longer packed */
+	ref->flags &= ~GIT_REF_PACKED;
+
 	return error == GIT_SUCCESS ?
 		git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") :
 		git__rethrow(error, "Failed to rename reference. Failed to rollback");