Skip to content

worktree mutations - #2977

Draft
Sebastian Thiel (Byron) wants to merge 16 commits into
mainfrom
worktree-create
Draft

Sebastian Thiel (Byron) wants to merge 16 commits into
mainfrom
worktree-create

Conversation

@Byron

@Byron Sebastian Thiel (Byron) commented Sep 8, 2026

Copy link
Copy Markdown
Member

Tasks

  • refackiew create
  • refackiew delete

@Byron
Sebastian Thiel (Byron) force-pushed the worktree-create branch 5 times, most recently from 7c42198 to 520efea Compare September 11, 2026 03:58
Comment thread gix/tests/gix/repository/worktree.rs Fixed
@Byron
Sebastian Thiel (Byron) force-pushed the worktree-create branch 10 times, most recently from 55f423f to 614b5a4 Compare September 14, 2026 13:18
<!-- agent -->
Paths such as `C:repo` previously replaced the supplied base with the `C:`
prefix and could remain relative. Resolve them against `cwd` when its drive
matches, including verbatim drive prefixes, and otherwise ask Windows for the
current directory on that drive.

Resolve only the drive prefix so subsequent symlinks are followed before
interpreting `..`. Document the base-directory rules and add regressions for
bare drives, matching and different drives, verbatim bases, fully qualified
paths, and symlink-sensitive parent traversal.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
…e Git conformant

<!-- agent -->
Replace leading dots before stripping repeated `.lock` suffixes, matching Git so
`.lock.lock` becomes `-lock` instead of losing its name. Handle empty sanitized
output without indexing it.

Keep `name_partial_or_sanitize()` returning `BString` and guarantee a nonempty
valid partial reference name. Empty or slash-only input falls back to `-`;
document this Gitoxide-specific behavior so callers need no empty-result
handling.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
<!-- agent -->
Shared repository modes need more than adding or replacing permission
bits: read-only files must stay read-only, executable files need execute
access wherever sharing grants read access, and directories need search
bits and Git's setgid defaults, including on macOS.

Follow Git's `calc_shared_perm()` and `adjust_shared_perm()`. Add
`set_shared_repository_permissions()` to apply the policy to an existing
path, skipping unchanged permissions and avoiding filesystem access for
a zero policy or on non-Unix platforms.

Require an explicit parsed sharing policy in `dir::create::Iter::new()`
and `dir::create::all()`. Apply it only to newly created directories,
preserving existing directory permissions. Configure retry limits with
`Iter::retries()`, which updates both the original and remaining counts.
Tests cover file modes, directory search and setgid bits, preservation of
existing directories, and retry limits reported in errors.

BREAKING CHANGE: `Iter::new(target, policy)` and
`dir::create::all(dir, retries, policy)` require a parsed sharing policy;
pass `0` to retain the previous umask behavior. Replace
`Iter::new_with_retries(target, retries)` with
`Iter::new(target, policy).retries(retries)`.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
<!-- agent -->
Temporary files created in shared repositories can require new parent
directories. Callers need those directories to honor the repository's
sharing policy even when the process umask would make them private.

Replace the tuple field of `ContainingDirectory::CreateAllRaceProof` with
named `retries` and `shared_repository_permissions` fields, and pass the
policy to directory creation in `gix_fs`. Setting the policy to `0`
preserves the previous umask behavior. Adapt the existing tempfile tests
to the new variant shape.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
…ries

<!-- agent -->
Locks in shared repositories need consistent permissions on both the lock
file and any parent directories created during acquisition. Adjusting only
the file can leave those directories inaccessible to other repository users.

Use one explicit parsed Git sharing policy for writable locks, markers,
and newly created directories. Apply it after the process umask in the
common acquisition path and forward it to `gix-tempfile` for directory
creation. A policy of `0` keeps the umask behavior without permission
metadata access. The adjusted file mode reaches the committed resource.

Keep `boundary_directory` as `Option<PathBuf>` and pass the sharing policy
separately. Replace custom-permission and symlink convenience methods with
`File::acquire()` and its optional resource resolver. Tests cover lock,
marker, and committed-resource modes, directory permissions, and rollback.

BREAKING CHANGE: acquisition methods require a `shared_repository_permissions`
argument; pass `0` for the previous umask behavior. `File::acquire()` takes
it before the optional resolver and no longer accepts a permission callback.
The `_with_permissions` and `_following_symlinks` convenience methods are
removed. Use `File::acquire()` with `Some(&acquire::resolve_symlink)` to
follow resource symlinks.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
<!-- agent -->
Add transactional linked-worktree administration with rollback, then compose
it in gix with existing reference, checkout, index, progress, and interruption
machinery.

Support attached and detached worktrees from bare or non-bare repositories while
rejecting occupied branches and destinations. Keep move, remove, repair, hooks,
sparse checkout, and relative-link configuration out of scope.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <codex@openai.com>
Expose `Repository::add_worktree()` for existing local branches and detached commits. Prepare the links, initialize `HEAD` and its reflog, check out the commit, and write the index, rolling back created files on failure or interruption.

Inherit worktree configuration and common attributes before checkout. Enumerate the main and linked repositories consistently so additions and branch deletion protect branches checked out or reserved by bisect and rebase, while matching Git's default namespace behavior.

Support `worktree.useRelativePaths` with its repository-format upgrade and `extensions.relativeWorktrees` validation. Compare behavior with Git for bare parents, separate Git directories, moved relative links, configuration inheritance, invalid destinations, and rollback.

Co-authored-by: Byron <sebastian.thiel@icloud.com>
Provide the `gix-worktree` plumbing needed to recursively remove a linked checkout and its private Git directory without following symbolic links or crossing Unix mount boundaries.

Use `dua-core` for traversal and parallel deletion with progress reporting, bounded retries for directory-not-empty races, and errors distinguishing checkout and administration failures. Keep repository validation, dirty-state checks, lock policy, and branch decisions with higher-level callers.

Include the opt-in crate feature, disposable-repository coverage, and the existing CLI adapter's required `dua-core` upgrade together so the workspace remains consistent.

Co-authored-by: Byron <sebastian.thiel@icloud.com>
Expose safe linked-worktree removal through `gix`, using the `gix-worktree` removal plumbing. Validate the selected worktree, inspect dirty and locked states, and preserve the checkout unless the requested removal policy permits deleting it.

Enable removal through `worktree-mutation` and report progress and cleanup outcomes to callers. Keep branch deletion explicit, adding compare-and-swap branch removal for callers that have already inspected a target so concurrent branch changes are not lost. Cover porcelain removal behavior and conditional branch deletion in disposable repositories.

Co-authored-by: Byron <sebastian.thiel@icloud.com>
Reference, index, and linked-worktree metadata writes must apply the effective `core.sharedRepository` policy after the process umask so other users can access shared repository data.

Cache the parsed policy in `gix`, refresh it after configuration changes, and pass it through loose and packed references, reflogs, clone checkout, status index updates, and the CLI and Tix index writers. Avoid redundant permission changes on already-shared reflogs owned by another user. Standalone index writers retain process-umask behavior by passing `0`.

Apply the same policy when preparing linked-worktree directories and linking files, writing `HEAD` and the index, and copying worktree configuration. Keep the private Git directory and checked-out contents at ordinary filesystem permissions. Include Git-baseline coverage and the deliberate extension of sharing to worktree linking files.

BREAKING CHANGE: `gix_index::File::write()` takes the signed sharing policy as its second argument, and `gix_worktree::add::Options` gains `shared_repository_permissions`. All workspace callers are adapted together; standalone callers can pass `0`.

Co-authored-by: Byron <sebastian.thiel@icloud.com>
…and clone

Deleting branch configuration and adopting a cloned remote's object format must preserve an existing configuration file's explicit permissions, even when `core.sharedRepository` is enabled.

Use the existing `FileTransaction` for both updates. This preserves the configuration mode and follows the transaction's symlink and locking behavior while retaining branch deletion's partial-success error reporting. Regression coverage checks that an explicit `0600` config stays private, matching Git.

BREAKING CHANGE: branch deletion and clone configuration failures expose `FileTransaction` errors instead of separate raw lock, read, write, and commit errors.
Initialization must resolve `core.sharedRepository` before it creates repository metadata; adjusting later writes leaves the Git directory, configuration, and template files inaccessible under a restrictive umask.

Load the permitted configuration scopes first, apply the sharing policy to the Git root and its metadata, and persist active sharing as Git does. Destination ancestors and the configuration-independent creation entry point retain their ordinary umask behavior.

Add a reusable subprocess helper for umask-sensitive tests, avoiding process-wide umask changes in concurrent tests. Compare initialized repositories and cloned metadata with Git under restrictive and ordinary umasks.
Shared refs are insufficient when loose objects remain private. Propagate the resolved repository policy through object-store initialization and each handle's loose-object writes, applying it before publishing objects and to newly created fanout directories.

Keep objects read-only. Runtime configuration changes and reloads affect the next write through the current handle without changing other handles, including cloned and thread-safe round trips. Cover both object hash formats and update the existing repository-size guard for the measured Windows layout.

BREAKING CHANGE: dynamic and loose object-store initialization options gain `shared_repository_permissions`. Standalone callers can retain umask behavior with `0`.
Fetching into a shared repository must make received packs, pack indices, and shallow boundaries accessible according to `core.sharedRepository`.

Pass the repository policy through pack-writing and protocol-fetch options. Create immutable pack and index files with appropriate initial permissions, share new destination directories, and keep `.keep` markers private. Preserve pre-existing markers and their ownership so the receiver does not remove another operation's marker. A tempfile constructor accepts creation permissions without bypassing the process umask.

BREAKING CHANGE: pack-writing and protocol-fetch options gain `shared_repository_permissions`. Repository callers pass their resolved policy; standalone callers pass `0`. The workspace adaptations and Git-baseline coverage are included together.
A multi-pack-index written into the selected repository must honor that repository's sharing policy. Leaving it at the process umask can make an otherwise shared object database inaccessible to other readers.

Resolve sharing for the default MIDX destination only when the selected repository owns that path, and pass the policy into its output lock. Explicit standalone destinations retain process-umask behavior. Extend the CLI journey coverage for repository-owned and standalone output.
The query database and its SQLite sidecars must be accessible to the same users as other shared repository data.

Apply `core.sharedRepository` immediately after opening the database, before SQLite creates journals, WALs, or shared-memory files that inherit its mode. Reapply the policy when schema-version changes recreate the database. Test initial creation, a live rollback journal, and recreation under ordinary and restrictive umasks.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants