configurable gitbutler storage path via Git config#12646
configurable gitbutler storage path via Git config#12646Byron merged 6 commits intogitbutlerapp:masterfrom
Conversation
|
@Byron is attempting to deploy a commit to the GitButler Team on Vercel. A member of the Team first needs to authorize it. |
fe8be93 to
8e345a8
Compare
c8b8a91 to
9b0be9a
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9b0be9a33a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Pull request overview
This PR makes per-repository GitButler storage location configurable via Git config and switches non-release builds to channel-isolated default storage directories, while transitioning project identifiers from legacy UUIDs to a self-describing ProjectHandle (and the ProjectHandleOrLegacyProjectId bridge type) across the Rust backend.
Changes:
- Add
but-project-handlecrate and a sharedgitbutler_storage_path()resolver (wired viabut_core::RepositoryExtand stored eagerly inbut_ctx::Context). - Migrate project identifiers throughout backend crates from
ProjectId/LegacyProjectIdtoProjectHandleOrLegacyProjectId. - Update tests/fixtures and activation flows to respect the configurable/channel-specific storage dir and avoid clobbering existing workspace refs.
Reviewed changes
Copilot reviewed 92 out of 93 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| etc/plans/consistent-data.md | Document ProjectId→ProjectHandle transition plan. |
| crates/gitbutler-watcher/src/lib.rs | Switch watcher handle to ProjectHandleOrLegacyProjectId. |
| crates/gitbutler-watcher/src/handler.rs | Open contexts from handle/legacy id; propagate new id type in events. |
| crates/gitbutler-watcher/src/events.rs | Update watcher Change payload project id type. |
| crates/gitbutler-watcher/Cargo.toml | Enable but-ctx legacy feature; drop direct gitbutler-project dep. |
| crates/gitbutler-testsupport/src/test_project.rs | Force stable .git/gitbutler in fixtures via storagePath config. |
| crates/gitbutler-testsupport/src/suite.rs | Handle Context::new_from_legacy_project_and_settings now returning Result. |
| crates/gitbutler-testsupport/src/lib.rs | Add test helper to set channel-aware storagePath config. |
| crates/gitbutler-tauri/src/zip.rs | Update archive APIs to accept ProjectHandleOrLegacyProjectId. |
| crates/gitbutler-tauri/src/window.rs | Update window state tracking and DB event conversion for new id type. |
| crates/gitbutler-tauri/src/projects.rs | Activate project via context conversion + activation preparation helper. |
| crates/gitbutler-tauri/src/claude.rs | Update Claude tauri commands to accept new project id type. |
| crates/gitbutler-tauri/src/bot.rs | Update bot tauri commands to accept new project id type. |
| crates/gitbutler-tauri/src/app.rs | Remove legacy App wrapper (deleted file). |
| crates/gitbutler-tauri/src/action.rs | Update actions tauri commands to accept new project id type. |
| crates/gitbutler-tauri/Cargo.toml | Enable but-ctx legacy feature explicitly. |
| crates/gitbutler-repo/tests/read_file_from_workspace_security.rs | Adapt to context constructor now returning Result. |
| crates/gitbutler-repo/tests/credentials.rs | Adapt to context constructor now returning Result. |
| crates/gitbutler-project/tests/project/main.rs | Add tests for configured storage directory behavior. |
| crates/gitbutler-project/src/storage.rs | Replace stored project id type with ProjectHandleOrLegacyProjectId. |
| crates/gitbutler-project/src/project.rs | Generate project ids as handles; resolve gb dir via resolver. |
| crates/gitbutler-project/src/lib.rs | Re-export handle types; update public APIs to new id type. |
| crates/gitbutler-project/src/controller.rs | Use handle ids; create/resume/delete storage dir via resolver. |
| crates/gitbutler-project/Cargo.toml | Add dependency on but-project-handle (legacy feature). |
| crates/gitbutler-filemonitor/tests/filemonitor/main.rs | Use project handle ids in filemonitor tests. |
| crates/gitbutler-filemonitor/src/file_monitor.rs | Switch monitor to use ProjectHandleOrLegacyProjectId. |
| crates/gitbutler-filemonitor/src/events.rs | Switch internal event ids to ProjectHandleOrLegacyProjectId. |
| crates/gitbutler-filemonitor/Cargo.toml | Add but-project-handle dep; extend tokio features. |
| crates/gitbutler-branch-actions/tests/virtual_branches/update_commit_message.rs | Adapt update request id cloning for new id type. |
| crates/gitbutler-branch-actions/tests/virtual_branches/oplog.rs | Use ctx.project_data_dir() for oplog path in tests. |
| crates/gitbutler-branch-actions/tests/virtual_branches/mod.rs | Switch test project id type + context creation. |
| crates/gitbutler-branch-actions/tests/virtual_branches/init.rs | Add test for preserving existing workspace ref on bootstrap. |
| crates/gitbutler-branch-actions/tests/virtual_branches/amend.rs | Adapt update request id cloning for new id type. |
| crates/gitbutler-branch-actions/src/base.rs | Add metadata-only bootstrap of default target when missing. |
| crates/gitbutler-branch-actions/Cargo.toml | Add but-project-handle dependency. |
| crates/but/src/command/legacy/mcp/mod.rs | Handle context creation returning Result. |
| crates/but-worktrees/tests/fixtures/scenario/shared.sh | Update fixture storage dir to .git/gitbutler.dev. |
| crates/but-tools/src/emit.rs | Switch emitted project id type to ProjectHandleOrLegacyProjectId. |
| crates/but-tools/Cargo.toml | Enable but-ctx legacy feature; drop direct gitbutler-project dep. |
| crates/but-testsupport/src/sandbox.rs | Resolve virtual_branches.toml path via gitbutler_storage_path(). |
| crates/but-testing/src/command/project.rs | Handle context creation returning Result. |
| crates/but-testing/src/command/mod.rs | Use project handle id in filemonitor spawning command. |
| crates/but-server/src/projects.rs | Track active projects by ProjectHandleOrLegacyProjectId; activation prep. |
| crates/but-server/src/lib.rs | Update server command params to new project id type. |
| crates/but-server/Cargo.toml | Enable but-ctx legacy feature; drop gitbutler-project dep. |
| crates/but-project-handle/tests/project-handle/storage_path.rs | Add resolver tests for configured/default storage path. |
| crates/but-project-handle/tests/project-handle/project_handle.rs | Add handle codec/serde tests. |
| crates/but-project-handle/tests/project-handle/main.rs | Test module entrypoint. |
| crates/but-project-handle/src/storage_path.rs | Implement storagePath resolution + channel defaults + uniqueness suffix. |
| crates/but-project-handle/src/project_handle.rs | Implement ProjectHandle + ProjectHandleOrLegacyProjectId wire format. |
| crates/but-project-handle/src/lib.rs | Define new transition crate exports and docs. |
| crates/but-project-handle/src/legacy_project_id.rs | Implement legacy UUID id type (feature-gated). |
| crates/but-project-handle/Cargo.toml | Add new crate manifest and deps. |
| crates/but-hunk-dependency/tests/fixtures/scenario/shared.sh | Update fixture storage dir to .git/gitbutler.dev. |
| crates/but-gitlab/Cargo.toml | Use workspace urlencoding dep. |
| crates/but-feedback/src/lib.rs | Update archival APIs to accept ProjectHandleOrLegacyProjectId. |
| crates/but-ctx/tests/fixtures/scenario/unborn-empty.sh | Add new repo fixture. |
| crates/but-ctx/tests/ctx/main.rs | Add tests for project handle contexts + config-driven project_data_dir. |
| crates/but-ctx/src/project_handle.rs | Add TryFrom<ProjectHandleOrLegacyProjectId> conversions to contexts. |
| crates/but-ctx/src/lib.rs | Store resolved project_data_dir in Context/ThreadSafeContext; add handle ctor. |
| crates/but-ctx/src/legacy.rs | Make legacy context constructors return Result and use resolver for DB dir. |
| crates/but-ctx/Cargo.toml | Add but-project-handle dep; wire legacy feature; add dev-deps. |
| crates/but-core/src/repo_ext.rs | Add RepositoryExt::gitbutler_storage_path() adapter method + docs. |
| crates/but-core/Cargo.toml | Add but-project-handle dependency. |
| crates/but-claude/src/session.rs | Clone project id where needed (non-Copy type). |
| crates/but-claude/src/lib.rs | Clone project id where needed (non-Copy type). |
| crates/but-claude/src/broadcaster.rs | Update broadcaster API to accept ProjectHandleOrLegacyProjectId. |
| crates/but-claude/Cargo.toml | Enable but-ctx legacy feature; drop gitbutler-project dep. |
| crates/but-cherry-apply/tests/fixtures/scenario/shared.sh | Update fixture storage dir to .git/gitbutler.dev. |
| crates/but-bot/src/state.rs | Switch agent state project id type; clone where needed. |
| crates/but-bot/src/lib.rs | Switch bot APIs to ProjectHandleOrLegacyProjectId. |
| crates/but-bot/src/butbot.rs | Switch bot internals to ProjectHandleOrLegacyProjectId. |
| crates/but-bot/Cargo.toml | Drop direct gitbutler-project dependency. |
| crates/but-api/src/schema.rs | Expose ProjectHandleOrLegacyProjectId schema as string. |
| crates/but-api/src/legacy/virtual_branches.rs | Clone id for update request (non-Copy). |
| crates/but-api/src/legacy/projects.rs | Accept handle/legacy ids, add activation preparation helper. |
| crates/but-api/src/legacy/mod.rs | Add helper to map handle/legacy ids to legacy project info. |
| crates/but-api/src/legacy/forge.rs | Clone id for validation call (non-Copy). |
| crates/but-api/src/legacy/claude.rs | Switch Claude API params to handle/legacy ids. |
| crates/but-api/Cargo.toml | Update feature docs for “legacy” requirement. |
| crates/but-api-macros/tests/tests/ui/pass/legacy_context_and_object_id.rs | Update macro UI test to accept handle/legacy ids. |
| crates/but-api-macros/tests/tests/ui/fail/default_cmd_requires_legacy.stderr | Add expected stderr for legacy-gated cmd wrapper test. |
| crates/but-api-macros/tests/tests/ui/fail/default_cmd_requires_legacy.rs | Add compile-fail test ensuring _cmd remains legacy-gated. |
| crates/but-api-macros/tests/tests/trybuild.rs | Gate default compile-fail tests when legacy is off. |
| crates/but-api-macros/tests/src/lib.rs | Clarify trybuild shim crate docs. |
| crates/but-api-macros/tests/Cargo.toml | Wire legacy feature to but-ctx/legacy. |
| crates/but-api-macros/src/lib.rs | Map Context params to ProjectHandleOrLegacyProjectId in wrapper generation. |
| crates/but-action/src/lib.rs | Switch auto-commit API to use handle/legacy ids. |
| crates/but-action/src/auto_commit.rs | Update event naming + token streaming to handle/legacy ids. |
| crates/but-action/Cargo.toml | Drop direct gitbutler-project dependency. |
| Cargo.toml | Add new crate to workspace; add workspace deps. |
| Cargo.lock | Update lockfile for new crate/dependency graph. |
| .github/copilot-instructions.md | Document preferred temporary directory strategy (use but-testsupport). |
fbf4100 to
3801ecf
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3801ecf781
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Resolve GitButler project storage from Git config and make non-release defaults channel-specific (.git/gitbutler.<channel>) so app channels do not interfere with incompatible database versions. Non-stable builds read gitbutler.<channel>.storagePath (for example gitbutler.nightly.storagePath), while release builds read gitbutler.storagePath. Relative paths are resolved against the repository git dir. This also allows moving project storage off unsuitable repository drives (e.g. NFS/network mounts), addressing SQLite lock/rename failures reported in gitbutlerapp#11157. Behavior notes: no automatic migration/fallback from legacy .git/gitbutler, defaults are computed in-memory (not auto-persisted to Git config), and path resolution now logs the effective storage path plus the config key to override it. Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
… don't clobber existing gitbutler/workspace refs Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
And thus integrate with it better.
My expectation is that concurrency semantics will be the same around all of our sqlite databases, so lets unify these parts at least.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5bc1e8f04f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
Document where per-project GitButler state lives and how to override it, including the channel-specific config keys and path constraints. Motivation: make the new storage path setting discoverable in the debugging docs for users who need to inspect or relocate repository-local GitButler state. Refs: gitbutlerapp/gitbutler#12646 Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
They are teaming up lately and don't look so good.
Before:
```
2026-03-09 10:30 +0800 Sebastian Thiel M─┐ [fix3] [master] {origin/HEAD} {origin/master} Merge pull request gitbutlerapp#12633 from Byron/codex/use-gix-id-shorten
2026-03-09 10:06 +0800 Sebastian Thiel │ o [codex/use-gix-id-shorten] {mine/codex/use-gix-id-shorten} Address Copilot and Codex review
2026-03-09 07:28 +0800 chatgpt-codex-connector[bot] │ o use gix::Id::shorten for legacy commit display IDs in `but` CLI
2026-03-09 07:23 +0800 Sebastian Thiel │ o Make it easy to get fast shorten performance.
2026-03-09 06:50 +0800 Sebastian Thiel M─┤ Merge pull request gitbutlerapp#12646 from Byron/next3
2026-03-09 06:31 +0800 chatgpt-codex-connector[bot] │ o [next3] {mine/next3} Address another round of reviews
````
After:
```
2026-03-09 10:30 +0800 Byron M─┐ [fix3] [master] {origin/HEAD} {origin/master} Merge pull request gitbutlerapp#12633 from Byron/codex/use-gix-id-shorten
2026-03-09 10:06 +0800 Byron │ o [codex/use-gix-id-shorten] {mine/codex/use-gix-id-shorten} Address Copilot and Codex review
2026-03-09 07:28 +0800 Codex │ o use gix::Id::shorten for legacy commit display IDs in `but` CLI
2026-03-09 07:23 +0800 Byron │ o Make it easy to get fast shorten performance.
2026-03-09 06:50 +0800 Byron M─┤ Merge pull request gitbutlerapp#12646 from Byron/next3
2026-03-09 06:31 +0800 Codex │ o [next3] {mine/next3} Address another round of reviews
````
`
`# Please enter the message for your patch. Lines starting with
Document where per-project GitButler state lives and how to override it, including the channel-specific config keys and path constraints. Motivation: make the new storage path setting discoverable in the debugging docs for users who need to inspect or relocate repository-local GitButler state. Refs: gitbutlerapp/gitbutler#12646 Co-authored-by: Sebastian Thiel <sebastian.thiel@icloud.com>
Fixes #11157 and resolves the issue of Nightly builds putting the database into the future, making it unreadable with the stable build.
As this new default for
.git/gitbutleris configurable, the user can force both build types toThis also means that non-stable channel builds will put their metadata into:
.git/gitbutler.nightly.git/gitbutler.devrespectively.
There is a new
gitbutler.storagePathconfiguration key, andgitbutler.<channel>.storagePathfor Nightly and Dev respectively. When set to to a relative path or path within.git/it allows to control the storage directory, for example as a way to make Nightly put its files to.git/gitbutlerinstead of.git/gitbutler.nightly.The
storagePathcan also be absolute to store project metadata side-by-side.Tasks
but-linka bit!Notes for the Reviewer
When running a dev version, it will now recreate its data in
.git/gitbutler.dev, causing it to want to re-initialise the workspace by picking the target branch. While it has been nerved to re-use existing gitbutler/workspace refs unconditionally, it's still something to go through.Screen.Recording.2026-03-08.at.17.04.27-Apple.Devices.SD.mov
Codex Plan
This will also happen to Nightly users.
Commit-Ready Plan: Configurable GitButler Storage Path with Channel Isolation
Summary
Change GitButler project storage to be resolved from Git config (
gitbutler.storagePath) and default non-stable builds to channel-specific storage paths (.git/gitbutler.<channel>).This addresses two motivations:
Scope and behavior
gitbutler.storagePath.gitbutler.storagePathis absolute: use it directly.gitbutler.storagePathis relative: resolve againstrepo.git_dir().<git_dir>/gitbutler.<git_dir>/gitbutler.<channel>.devand use<git_dir>/gitbutler.dev..git/gitbutler..git/config.Required implementation changes
but-core(RepositoryExt) so all callers use one implementation.but-ctx::Contextto store the resolved project-data directory eagerly at creation time.Contextconstructors create/open a real repository before finalizing context so full Git config is available.Contextthrough the resolved project-data directory, not a hardcodedgitdir.join("gitbutler").gitbutler-projectadd/get/delete storage dir operations) to use the same resolver logic..git/gitbutler.Public API / interface changes
gitbutler.storagePath.RepositoryExtmethod for resolved storage path.Context::project_data_dir()becomes config-aware instead of hardcoded.Contextand thread-safe context equivalents carry the resolved project-data directory as state.Testing and acceptance criteria
<git_dir>/gitbutler.<git_dir>/gitbutler.nightly.<git_dir>/gitbutler.<channel>.git_dir.project_data_dir..git/gitbutler.Rollout and compatibility notes
.git/gitbutlerdata will start isolated storage by default.gitbutler.storagePathto a local filesystem path suitable for SQLite.Proposed commit message
Subject
ctx/project: make storage path git-configurable and channel-isolatedBody
Resolve GitButler project storage from gitbutler.storagePath and make non-release defaults channel-specific (.git/gitbutler.<channel>) to prevent channel interference from incompatible DB versions.This also enables moving project storage off unsuitable repository drives (e.g. NFS/network mounts), addressing SQLite lock/rename failures reported in #11157.Behavior notes: no automatic migration/fallback from legacy .git/gitbutler, and defaults are computed in-memory (not auto-persisted to git config).Assumptions locked
gitbutler.storagePath.git_dir-relative.gitbutler-projectstorage directory operations are included in this same change.