Skip to content

Commit 6e4b5f2

Browse files
stevenpollackclaude
andcommitted
fix(worktrees): create missing parent dirs when adding a worktree
libgit2's `Repository::worktree` creates only the leaf directory, not missing parents (unlike `git worktree add`), so a nested path such as `worktrees/test-wt-2` failed with "failed to make directory ...: No such file or directory" when the parent did not exist. Create the parent chain via `create_dir_all` before the git2 call. Adds a regression test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BMQxBdr5f3B3jmDtdvGtTu
1 parent 46a2bf9 commit 6e4b5f2

1 file changed

Lines changed: 28 additions & 0 deletions

File tree

asyncgit/src/sync/worktree.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,13 @@ pub fn create_worktree(
155155
})?
156156
.to_string();
157157

158+
// libgit2 only creates the leaf directory, not missing parents
159+
// (unlike `git worktree add`), so create the parent chain first
160+
// to support nested paths such as `worktrees/foo`.
161+
if let Some(parent) = target.parent() {
162+
std::fs::create_dir_all(parent)?;
163+
}
164+
158165
let worktree = repo.worktree(&name, &target, None)?;
159166

160167
Ok(worktree.path().to_path_buf())
@@ -287,6 +294,27 @@ mod tests {
287294
assert!(!wt.is_current);
288295
}
289296

297+
#[test]
298+
fn test_create_worktree_creates_missing_parents() {
299+
let (_td, repo) = repo_init().unwrap();
300+
let root = repo.path().parent().unwrap();
301+
let repo_path: RepoPath = root.to_str().unwrap().into();
302+
303+
// nested path whose parent dirs do not exist yet; libgit2
304+
// would fail to mkdir the leaf without this being handled.
305+
let wt_dir = tempfile::TempDir::new().unwrap();
306+
let nested = wt_dir.path().join("a").join("b").join("wt");
307+
308+
let created =
309+
create_worktree(&repo_path, nested.to_str().unwrap())
310+
.unwrap();
311+
312+
assert!(created.ends_with("wt"));
313+
let list = get_worktrees(&repo_path).unwrap();
314+
let wt = find(&list, "wt");
315+
assert_eq!(wt.branch.as_deref(), Some("wt"));
316+
}
317+
290318
#[test]
291319
fn test_create_worktree_rejects_pathless_name() {
292320
let (_td, repo) = repo_init().unwrap();

0 commit comments

Comments
 (0)