Skip to content

Commit 765c225

Browse files
MadCodergitster
authored andcommitted
fix git branch -m in presence of cross devices
When you have for example a bare repository stored on NFS, and that you create new workdirs locally (using contrib's git-new-workdir), logs/refs is a symlink to a different device. Hence when the reflogs are renamed, all must happen below logs/refs or one gets cross device rename errors like: git branch -m foo error: unable to move logfile logs/refs/heads/master to tmp-renamed-log: Invalid cross-device link fatal: Branch rename failed The fix is hence to use logs/refs/.tmp-renamed-log as a temporary log name, instead of just tmp-renamed-log. Signed-off-by: Pierre Habouzit <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 420432d commit 765c225

File tree

1 file changed

+15
-6
lines changed

1 file changed

+15
-6
lines changed

refs.c

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,6 +1086,15 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
10861086
return ret;
10871087
}
10881088

1089+
/*
1090+
* People using contrib's git-new-workdir have .git/logs/refs ->
1091+
* /some/other/path/.git/logs/refs, and that may live on another device.
1092+
*
1093+
* IOW, to avoid cross device rename errors, the temporary renamed log must
1094+
* live into logs/refs.
1095+
*/
1096+
#define TMP_RENAMED_LOG "logs/refs/.tmp-renamed-log"
1097+
10891098
int rename_ref(const char *oldref, const char *newref, const char *logmsg)
10901099
{
10911100
static const char renamed_ref[] = "RENAMED-REF";
@@ -1119,8 +1128,8 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
11191128
if (write_ref_sha1(lock, orig_sha1, logmsg))
11201129
return error("unable to save current sha1 in %s", renamed_ref);
11211130

1122-
if (log && rename(git_path("logs/%s", oldref), git_path("tmp-renamed-log")))
1123-
return error("unable to move logfile logs/%s to tmp-renamed-log: %s",
1131+
if (log && rename(git_path("logs/%s", oldref), git_path(TMP_RENAMED_LOG)))
1132+
return error("unable to move logfile logs/%s to "TMP_RENAMED_LOG": %s",
11241133
oldref, strerror(errno));
11251134

11261135
if (delete_ref(oldref, orig_sha1, REF_NODEREF)) {
@@ -1146,7 +1155,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
11461155
}
11471156

11481157
retry:
1149-
if (log && rename(git_path("tmp-renamed-log"), git_path("logs/%s", newref))) {
1158+
if (log && rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newref))) {
11501159
if (errno==EISDIR || errno==ENOTDIR) {
11511160
/*
11521161
* rename(a, b) when b is an existing
@@ -1159,7 +1168,7 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
11591168
}
11601169
goto retry;
11611170
} else {
1162-
error("unable to move logfile tmp-renamed-log to logs/%s: %s",
1171+
error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
11631172
newref, strerror(errno));
11641173
goto rollback;
11651174
}
@@ -1199,8 +1208,8 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg)
11991208
error("unable to restore logfile %s from %s: %s",
12001209
oldref, newref, strerror(errno));
12011210
if (!logmoved && log &&
1202-
rename(git_path("tmp-renamed-log"), git_path("logs/%s", oldref)))
1203-
error("unable to restore logfile %s from tmp-renamed-log: %s",
1211+
rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", oldref)))
1212+
error("unable to restore logfile %s from "TMP_RENAMED_LOG": %s",
12041213
oldref, strerror(errno));
12051214

12061215
return 1;

0 commit comments

Comments
 (0)