Match branches with worktrees always, even with slashes
This commit is contained in:
@@ -502,25 +502,9 @@ fn main() {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut name: &str = &action_args.name;
|
|
||||||
let subdirectory;
|
|
||||||
let split = name.split_once('/');
|
|
||||||
match split {
|
|
||||||
None => subdirectory = None,
|
|
||||||
Some(split) => {
|
|
||||||
if split.0.is_empty() || split.1.is_empty() {
|
|
||||||
print_error("Worktree name cannot start or end with a slash");
|
|
||||||
process::exit(1);
|
|
||||||
} else {
|
|
||||||
(subdirectory, name) = (Some(Path::new(split.0)), split.1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match worktree::add_worktree(
|
match worktree::add_worktree(
|
||||||
&cwd,
|
&cwd,
|
||||||
name,
|
&action_args.name,
|
||||||
subdirectory,
|
|
||||||
track,
|
track,
|
||||||
action_args.no_track,
|
action_args.no_track,
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ fn sync_repo(root_path: &Path, repo: &repo::Repo, init_worktree: bool) -> Result
|
|||||||
if newly_created && repo.worktree_setup && init_worktree {
|
if newly_created && repo.worktree_setup && init_worktree {
|
||||||
match repo_handle.default_branch() {
|
match repo_handle.default_branch() {
|
||||||
Ok(branch) => {
|
Ok(branch) => {
|
||||||
worktree::add_worktree(&repo_path, &branch.name()?, None, None, false)?;
|
worktree::add_worktree(&repo_path, &branch.name()?, None, false)?;
|
||||||
}
|
}
|
||||||
Err(_error) => print_repo_error(
|
Err(_error) => print_repo_error(
|
||||||
&repo.name,
|
&repo.name,
|
||||||
|
|||||||
@@ -21,10 +21,17 @@ pub const GIT_MAIN_WORKTREE_DIRECTORY: &str = ".git-main-working-tree";
|
|||||||
pub fn add_worktree(
|
pub fn add_worktree(
|
||||||
directory: &Path,
|
directory: &Path,
|
||||||
name: &str,
|
name: &str,
|
||||||
subdirectory: Option<&Path>,
|
|
||||||
track: Option<(&str, &str)>,
|
track: Option<(&str, &str)>,
|
||||||
no_track: bool,
|
no_track: bool,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
|
// A branch name must never start or end with a slash. Everything else is ok.
|
||||||
|
if name.starts_with('/') || name.ends_with('/') {
|
||||||
|
return Err(format!(
|
||||||
|
"Invalid worktree name: {}. It cannot start or end with a slash",
|
||||||
|
name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
let repo = repo::RepoHandle::open(directory, true).map_err(|error| match error.kind {
|
let repo = repo::RepoHandle::open(directory, true).map_err(|error| match error.kind {
|
||||||
repo::RepoErrorKind::NotFound => {
|
repo::RepoErrorKind::NotFound => {
|
||||||
String::from("Current directory does not contain a worktree setup")
|
String::from("Current directory does not contain a worktree setup")
|
||||||
@@ -38,11 +45,6 @@ pub fn add_worktree(
|
|||||||
return Err(format!("Worktree {} already exists", &name));
|
return Err(format!("Worktree {} already exists", &name));
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = match subdirectory {
|
|
||||||
Some(dir) => directory.join(dir).join(name),
|
|
||||||
None => directory.join(Path::new(name)),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut remote_branch_exists = false;
|
let mut remote_branch_exists = false;
|
||||||
|
|
||||||
let mut target_branch = match repo.find_local_branch(name) {
|
let mut target_branch = match repo.find_local_branch(name) {
|
||||||
@@ -193,10 +195,80 @@ pub fn add_worktree(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(subdirectory) = subdirectory {
|
// We have to create subdirectories first, otherwise adding the worktree
|
||||||
std::fs::create_dir_all(subdirectory).map_err(|error| error.to_string())?;
|
// will fail
|
||||||
|
if name.contains('/') {
|
||||||
|
let path = Path::new(&name);
|
||||||
|
if let Some(base) = path.parent() {
|
||||||
|
// This is a workaround of a bug in libgit2 (?)
|
||||||
|
//
|
||||||
|
// When *not* doing this, we will receive an error from the `Repository::worktree()`
|
||||||
|
// like this:
|
||||||
|
//
|
||||||
|
// > failed to make directory '/{repo}/.git-main-working-tree/worktrees/dir/test
|
||||||
|
//
|
||||||
|
// This is a discrepancy between the behaviour of libgit2 and the
|
||||||
|
// git CLI when creating worktrees with slashes:
|
||||||
|
//
|
||||||
|
// The git CLI will create the worktree's configuration directory
|
||||||
|
// inside {git_dir}/worktrees/{last_path_component}. Look at this:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// $ git worktree add 1/2/3 -b 1/2/3
|
||||||
|
// $ ls .git/worktrees
|
||||||
|
// 3
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// Interesting: When adding a worktree with a different name but the
|
||||||
|
// same final path component, git starts adding a counter suffix to
|
||||||
|
// the worktree directories:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// $ git worktree add 1/3/3 -b 1/3/3
|
||||||
|
// $ git worktree add 1/4/3 -b 1/4/3
|
||||||
|
// $ ls .git/worktrees
|
||||||
|
// 3
|
||||||
|
// 31
|
||||||
|
// 32
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// I *guess* that the mapping back from the worktree directory under .git to the actual
|
||||||
|
// worktree directory is done via the `gitdir` file inside `.git/worktrees/{worktree}.
|
||||||
|
// This means that the actual directory would not matter. You can verify this by
|
||||||
|
// just renaming it:
|
||||||
|
//
|
||||||
|
// ```
|
||||||
|
// $ mv .git/worktrees/3 .git/worktrees/foobar
|
||||||
|
// $ git worktree list
|
||||||
|
// /tmp/ fcc8a2a7 [master]
|
||||||
|
// /tmp/1/2/3 fcc8a2a7 [1/2/3]
|
||||||
|
// /tmp/1/3/3 fcc8a2a7 [1/3/3]
|
||||||
|
// /tmp/1/4/3 fcc8a2a7 [1/4/3]
|
||||||
|
// ```
|
||||||
|
//
|
||||||
|
// => Still works
|
||||||
|
//
|
||||||
|
// Anyway, libgit2 does not do this: It tries to create the worktree
|
||||||
|
// directory inside .git with the exact name of the worktree, including
|
||||||
|
// any slashes. It should be this code:
|
||||||
|
//
|
||||||
|
// https://github.com/libgit2/libgit2/blob/f98dd5438f8d7bfd557b612fdf1605b1c3fb8eaf/src/libgit2/worktree.c#L346
|
||||||
|
//
|
||||||
|
// As a workaround, we can create the base directory manually for now.
|
||||||
|
//
|
||||||
|
// Tracking upstream issue: https://github.com/libgit2/libgit2/issues/6327
|
||||||
|
std::fs::create_dir_all(
|
||||||
|
directory
|
||||||
|
.join(GIT_MAIN_WORKTREE_DIRECTORY)
|
||||||
|
.join("worktrees")
|
||||||
|
.join(base),
|
||||||
|
)
|
||||||
|
.map_err(|error| error.to_string())?;
|
||||||
|
std::fs::create_dir_all(base).map_err(|error| error.to_string())?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
repo.new_worktree(name, &path, &target_branch)?;
|
|
||||||
|
repo.new_worktree(name, &directory.join(&name), &target_branch)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user