return ret;
}
-int rename_ref(const char *oldref, const char *newref)
+/*
+ * People using contrib's git-new-workdir have .git/logs/refs ->
+ * /some/other/path/.git/logs/refs, and that may live on another device.
+ *
+ * IOW, to avoid cross device rename errors, the temporary renamed log must
+ * live into logs/refs.
+ */
+#define TMP_RENAMED_LOG "logs/refs/.tmp-renamed-log"
+
+int rename_ref(const char *oldref, const char *newref, const char *logmsg)
{
- static const char renamed_ref[] = "RENAMED-REF";
unsigned char sha1[20], orig_sha1[20];
int flag = 0, logmoved = 0;
struct ref_lock *lock;
- char msg[PATH_MAX*2 + 100];
struct stat loginfo;
- int log = !stat(git_path("logs/%s", oldref), &loginfo);
+ int log = !lstat(git_path("logs/%s", oldref), &loginfo);
+ const char *symref = NULL;
- if (S_ISLNK(loginfo.st_mode))
+ if (log && S_ISLNK(loginfo.st_mode))
return error("reflog for %s is a symlink", oldref);
- if (!resolve_ref(oldref, orig_sha1, 1, &flag))
+ symref = resolve_ref(oldref, orig_sha1, 1, &flag);
+ if (flag & REF_ISSYMREF)
+ return error("refname %s is a symbolic ref, renaming it is not supported",
+ oldref);
+ if (!symref)
return error("refname %s not found", oldref);
- if (!is_refname_available(newref, oldref, get_packed_refs(), 0))
+ if (!is_refname_available(newref, oldref, get_packed_refs(NULL), 0))
return 1;
- if (!is_refname_available(newref, oldref, get_loose_refs(), 0))
+ if (!is_refname_available(newref, oldref, get_loose_refs(NULL), 0))
return 1;
- lock = lock_ref_sha1_basic(renamed_ref, NULL, 0, NULL);
- if (!lock)
- return error("unable to lock %s", renamed_ref);
- lock->force_write = 1;
- if (write_ref_sha1(lock, orig_sha1, logmsg))
- return error("unable to save current sha1 in %s", renamed_ref);
- if (snprintf(msg, sizeof(msg), "renamed %s to %s", oldref, newref) > sizeof(msg))
- return error("Refnames to long");
--
- if (log && rename(git_path("logs/%s", oldref), git_path("tmp-renamed-log")))
- return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
+ if (log && rename(git_path("logs/%s", oldref), git_path(TMP_RENAMED_LOG)))
+ return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
oldref, strerror(errno));
- if (delete_ref(oldref, orig_sha1)) {
+ if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
error("unable to delete old %s", oldref);
goto rollback;
}