mirror of
https://github.com/openai/codex.git
synced 2026-09-11 20:36:49 +00:00
## What changed - Add `WorktreeManager::create` to create detached, Desktop-compatible worktrees from `HEAD` or an explicit base while preserving the source working-directory path. - Isolate worktree Git operations from inherited repository selectors, hooks, filesystem monitors, and configured content filters. - Validate the destination working directory and roll back incomplete worktrees and empty allocation buckets on failure. ## Testing - Cover layout, base selection, annotated tags, nested working directories, Git environment isolation, filter suppression, source checkout preservation, unsafe symlinks, and creation rollback. GitOrigin-RevId: bf172c3ff4268dab603d00a1d547485fcd0de368
47 lines
1.4 KiB
Rust
47 lines
1.4 KiB
Rust
//! Allocates Desktop-compatible worktree buckets and removes empty buckets.
|
|
|
|
use anyhow::Context;
|
|
use anyhow::Result;
|
|
use anyhow::bail;
|
|
use std::ffi::OsStr;
|
|
use std::fs;
|
|
use std::io;
|
|
use std::path::Path;
|
|
use std::path::PathBuf;
|
|
use uuid::Uuid;
|
|
|
|
pub(crate) fn allocate_worktree_root(root: &Path, repository_name: &OsStr) -> Result<PathBuf> {
|
|
fs::create_dir_all(root)
|
|
.with_context(|| format!("cannot create worktree root {}", root.display()))?;
|
|
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
let marker = root.join(".metadata_never_index");
|
|
fs::write(&marker, b"").with_context(|| {
|
|
format!("cannot disable Spotlight indexing at {}", marker.display())
|
|
})?;
|
|
}
|
|
|
|
for _ in 0..=u16::MAX {
|
|
let identifier = Uuid::new_v4().simple().to_string();
|
|
let bucket = root.join(&identifier[..4]);
|
|
match fs::create_dir(&bucket) {
|
|
Ok(()) => return Ok(bucket.join(repository_name)),
|
|
Err(error) if error.kind() == io::ErrorKind::AlreadyExists => {}
|
|
Err(error) => {
|
|
return Err(error).with_context(|| {
|
|
format!("cannot create worktree bucket {}", bucket.display())
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
bail!("all managed worktree identifiers are in use")
|
|
}
|
|
|
|
pub(crate) fn remove_empty_bucket(checkout: &Path) {
|
|
if let Some(bucket) = checkout.parent() {
|
|
let _ = fs::remove_dir(bucket);
|
|
}
|
|
}
|