When creating a new worktree by git worktree add foo <revision>
, in the main worktree .git/worktrees/foo/
is also created. I've encountered a situation several times, where it creates .git/worktrees/foo1/
instead. I think 1
is appended because there are some naming conflicts. I'd like to know why this happens and how to replicate the case. Thanks.
FYI, multiple threads may work in the same main worktree to create different worktrees, and git version 2.31.1 on Ubuntu.
CodePudding user response:
The git worktree add
code synthesizes the worktree ID (internal name) in add_worktree
, using this loop:
if (safe_create_leading_directories_const(sb_repo.buf))
die_errno(_("could not create leading directories of '%s'"),
sb_repo.buf);
while (mkdir(sb_repo.buf, 0777)) {
counter ;
if ((errno != EEXIST) || !counter /* overflow */)
die_errno(_("could not create directory of '%s'"),
sb_repo.buf);
strbuf_setlen(&sb_repo, len);
strbuf_addf(&sb_repo, "%d", counter);
}
name = strrchr(sb_repo.buf, '/') 1;
The initial sb_repo.buf
consists of a "sanitized" name derived from the path, where in your case the path is the name foo
added to the Git directory and the worktrees subdirectory ($GIT_DIR/worktrees/foo
). The len
here is the point where the numeric suffix part goes in. So, if the initial mkdir
call fails with EEXIST
, the foo
part of the sb_repo.buf
strbuf is replaced with foo1
, foo2
, and so on, until the mkdir
call either succeeds (returns 0) or fails with something other than EEXIST
.
[Sometimes Git] creates
.git/worktrees/foo1/
instead. I think 1 is appended because there are some naming conflicts.
This would happen if there's already a .git/worktrees/foo
, so that the mkdir
call returned an error with EEXIST
as the error number. That in turn would happen if there were a worktree whose path ended with foo
, or something that sanitized to foo
.]
[Note that you can also see random errors with Git repositories when they are stored in a cloud-synced folder (ICloud, Dropbox, etc). The cloud-syncing software reaches into the repository and damages it in its attempt to synchronize it. That's probably not the case here though.]
(It's a bit curious as to why you care where the worktree-specific files live inside $GIT_DIR
. I'm not sure why Git goes to all this effort to make a base name, rather than just generating randomized IDs using mkdtemp
or an equivalent: had Git done that, people would not be tempted to poke around inside .git/worktrees
as much. To use worktree-specific refs like HEAD
and bisect revision names, use git rev-parse
or git update-ref
, which knows how to do this on its own. There is, I think, a bit of a problem with temporary index files: the index file needs to be per-worktree, and it would be nice to have git rev-parse --git-internal-worktree-path
or some such for constructing such names.)