{"thread":{"id":"24316","subject":"[PATCH] fix git branch -m in presence of cross devices","startedAt":"2010-07-07T07:47:20Z","lastAt":"2010-07-07T07:47:20Z","messageCount":1,"participants":["Pierre Habouzit"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"145008","messageId":"20100707074720.GB26033@madism.org","threadId":"24316","inReplyTo":null,"subject":"[PATCH] fix git branch -m in presence of cross devices","fromName":"Pierre Habouzit","fromEmail":"madcoder@debian.org","sentAt":"2010-07-07T07:47:20Z","receivedAt":"2010-07-07T07:47:20Z","isPatch":true,"sender":{"key":"madcoder@debian.org","avatar":"https://avatars.githubusercontent.com/u/44708?v=4"},"body":"When you have for example a bare repository stored on NFS, and that you\ncreate new workdirs locally (using contrib's git-new-workdir), logs/refs\nis a symlink to a different device. Hence when the reflogs are renamed,\nall must happen below logs/refs or one gets cross device rename errors\nlike:\n\n  git branch -m foo\n  error: unable to move logfile logs/refs/heads/master to tmp-renamed-log: Invalid cross-device link\n  fatal: Branch rename failed\n\nThe fix is hence to use logs/refs/.tmp-renamed-log as a temporary log\nname, instead of just tmp-renamed-log.\n\nSigned-off-by: Pierre Habouzit <madcoder@debian.org>\n---\n refs.c |   21 +++++++++++++++------\n 1 files changed, 15 insertions(+), 6 deletions(-)\n\ndiff --git a/refs.c b/refs.c\nindex 6f486ae..b540067 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1090,6 +1090,15 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)\n \treturn ret;\n }\n \n+/*\n+ * People using contrib's git-new-workdir have .git/logs/refs ->\n+ * /some/other/path/.git/logs/refs, and that may live on another device.\n+ *\n+ * IOW, to avoid cross device rename errors, the temporary renamed log must\n+ * live into logs/refs.\n+ */\n+#define TMP_RENAMED_LOG  \"logs/refs/.tmp-renamed-log\"\n+\n int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n {\n \tstatic const char renamed_ref[] = \"RENAMED-REF\";\n@@ -1123,8 +1132,8 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \tif (write_ref_sha1(lock, orig_sha1, logmsg))\n \t\treturn error(\"unable to save current sha1 in %s\", renamed_ref);\n \n-\tif (log && rename(git_path(\"logs/%s\", oldref), git_path(\"tmp-renamed-log\")))\n-\t\treturn error(\"unable to move logfile logs/%s to tmp-renamed-log: %s\",\n+\tif (log && rename(git_path(\"logs/%s\", oldref), git_path(TMP_RENAMED_LOG)))\n+\t\treturn error(\"unable to move logfile logs/%s to \"TMP_RENAMED_LOG\": %s\",\n \t\t\toldref, strerror(errno));\n \n \tif (delete_ref(oldref, orig_sha1, REF_NODEREF)) {\n@@ -1150,7 +1159,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \t}\n \n  retry:\n-\tif (log && rename(git_path(\"tmp-renamed-log\"), git_path(\"logs/%s\", newref))) {\n+\tif (log && rename(git_path(TMP_RENAMED_LOG), git_path(\"logs/%s\", newref))) {\n \t\tif (errno==EISDIR || errno==ENOTDIR) {\n \t\t\t/*\n \t\t\t * rename(a, b) when b is an existing\n@@ -1163,7 +1172,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \t\t\t}\n \t\t\tgoto retry;\n \t\t} else {\n-\t\t\terror(\"unable to move logfile tmp-renamed-log to logs/%s: %s\",\n+\t\t\terror(\"unable to move logfile \"TMP_RENAMED_LOG\" to logs/%s: %s\",\n \t\t\t\tnewref, strerror(errno));\n \t\t\tgoto rollback;\n \t\t}\n@@ -1203,8 +1212,8 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)\n \t\terror(\"unable to restore logfile %s from %s: %s\",\n \t\t\toldref, newref, strerror(errno));\n \tif (!logmoved && log &&\n-\t    rename(git_path(\"tmp-renamed-log\"), git_path(\"logs/%s\", oldref)))\n-\t\terror(\"unable to restore logfile %s from tmp-renamed-log: %s\",\n+\t    rename(git_path(TMP_RENAMED_LOG), git_path(\"logs/%s\", oldref)))\n+\t\terror(\"unable to restore logfile %s from \"TMP_RENAMED_LOG\": %s\",\n \t\t\toldref, strerror(errno));\n \n \treturn 1;\n-- \n1.7.2.rc1.212.g850a.dirty\n"}]}