summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRonnie Sahlberg <sahlberg@google.com>2014-05-15 10:29:58 -0700
committerJunio C Hamano <gitster@pobox.com>2014-05-15 14:12:41 -0700
commit522df67d8c13a60e8dc5aaa8686d3d7bd527bcef (patch)
tree54ff26c050c26df2e7b5b21d1a1fcf28cefabee0
parent959d0cbf938821b856660498e7992a48ece2718b (diff)
downloadgit-522df67d8c13a60e8dc5aaa8686d3d7bd527bcef.tar.gz
refs.c: make rename_ref use a transaction
Change rename_ref to use a single transaction to perform the ref rename. Signed-off-by: Ronnie Sahlberg <sahlberg@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--refs.c73
1 files changed, 20 insertions, 53 deletions
diff --git a/refs.c b/refs.c
index c9405099d3..336df40163 100644
--- a/refs.c
+++ b/refs.c
@@ -2602,9 +2602,10 @@ static int rename_tmp_log(const char *newrefname)
int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
{
- unsigned char sha1[20], orig_sha1[20];
- int flag = 0, logmoved = 0;
- struct ref_lock *lock;
+ unsigned char sha1[20];
+ int flag = 0;
+ struct ref_transaction *transaction;
+ struct strbuf err = STRBUF_INIT;
struct stat loginfo;
int log = !lstat(git_path("logs/%s", oldrefname), &loginfo);
const char *symref = NULL;
@@ -2615,7 +2616,7 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldrefname);
- symref = resolve_ref_unsafe(oldrefname, orig_sha1, 1, &flag);
+ symref = resolve_ref_unsafe(oldrefname, sha1, 1, &flag);
if (flag & REF_ISSYMREF)
return error("refname %s is a symbolic ref, renaming it is not supported",
oldrefname);
@@ -2637,62 +2638,28 @@ int rename_ref(const char *oldrefname, const char *newrefname, const char *logms
if (pack_refs(PACK_REFS_ALL | PACK_REFS_PRUNE))
return error("unable to pack refs");
- if (delete_ref(oldrefname, orig_sha1, REF_NODEREF)) {
- error("unable to delete old %s", oldrefname);
- goto rollback;
- }
-
- if (!read_ref_full(newrefname, sha1, 1, NULL) &&
- delete_ref(newrefname, sha1, REF_NODEREF)) {
- if (errno==EISDIR) {
- if (remove_empty_directories(git_path("%s", newrefname))) {
- error("Directory not empty: %s", newrefname);
- goto rollback;
- }
- } else {
- error("unable to delete existing %s", newrefname);
- goto rollback;
- }
+ transaction = ref_transaction_begin();
+ if (!transaction ||
+ ref_transaction_delete(transaction, oldrefname, sha1,
+ REF_NODEREF | REF_ISPACKONLY,
+ 1, NULL) ||
+ ref_transaction_update(transaction, newrefname, sha1,
+ NULL, 0, 0, logmsg) ||
+ ref_transaction_commit(transaction, &err)) {
+ ref_transaction_rollback(transaction);
+ error("rename_ref failed: %s", err.buf);
+ strbuf_release(&err);
+ goto rollbacklog;
}
+ ref_transaction_free(transaction);
if (log && rename_tmp_log(newrefname))
- goto rollback;
-
- logmoved = log;
-
- lock = lock_ref_sha1_basic(newrefname, NULL, 0, NULL, NULL, 0);
- if (!lock) {
- error("unable to lock %s for update", newrefname);
- goto rollback;
- }
- lock->force_write = 1;
- hashcpy(lock->old_sha1, orig_sha1);
- if (write_ref_sha1(lock, orig_sha1, logmsg)) {
- error("unable to write current sha1 into %s", newrefname);
- goto rollback;
- }
-
- return 0;
-
- rollback:
- lock = lock_ref_sha1_basic(oldrefname, NULL, 0, NULL, NULL, 0);
- if (!lock) {
- error("unable to lock %s for rollback", oldrefname);
goto rollbacklog;
- }
- lock->force_write = 1;
- flag = log_all_ref_updates;
- log_all_ref_updates = 0;
- if (write_ref_sha1(lock, orig_sha1, NULL))
- error("unable to write current sha1 into %s", oldrefname);
- log_all_ref_updates = flag;
+ return 0;
rollbacklog:
- if (logmoved && rename(git_path("logs/%s", newrefname), git_path("logs/%s", oldrefname)))
- error("unable to restore logfile %s from %s: %s",
- oldrefname, newrefname, strerror(errno));
- if (!logmoved && log &&
+ if (log &&
rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldrefname)))
error("unable to restore logfile %s from "TMP_RENAMED_LOG": %s",
oldrefname, strerror(errno));