If a directory vanishes while renaming the temporary reflog file, retry (up to 3 times). This could happen if another process deletes the directory created by safe_create_leading_directories() just before we rename the file into the directory. As far as I can tell, this race could not occur internal to git. The only time that a directory under $GIT_DIR/logs is deleted is if room has to be made for a log file for a reference with the same name; for example, in the following sequence: git branch foo/bar # Creates file .git/logs/refs/heads/foo/bar git branch -d foo/bar # Deletes file but leaves .git/logs/refs/heads/foo/ git branch foo # Deletes .git/logs/refs/heads/foo/ But the only reason the last command deletes the directory is because it wants to create a file with the same name. So if another process (e.g., git branch foo/baz ) wants to create that directory, one of the two is doomed to failure anyway because of a D/F conflict. Signed-off-by: Michael Haggerty <mhagger@xxxxxxxxxxxx> --- refs.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/refs.c b/refs.c index 5bc01a7..8de636e 100644 --- a/refs.c +++ b/refs.c @@ -2530,12 +2530,14 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt) static int rename_tmp_log(const char *newrefname) { + int attempts = 3; + + retry: if (safe_create_leading_directories(git_path("logs/%s", newrefname))) { error("unable to create directory for %s", newrefname); return -1; } - retry: if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) { if (errno==EISDIR || errno==ENOTDIR) { /* @@ -2548,6 +2550,13 @@ static int rename_tmp_log(const char *newrefname) return -1; } goto retry; + } else if (errno == ENOENT && --attempts > 0) { + /* + * Maybe another process just deleted one of + * the directories in the path to newrefname. + * Try again from the beginning. + */ + goto retry; } else { error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s", newrefname, strerror(errno)); -- 1.8.5.2 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html