Skip to content

Commit a7c1211

Browse files
committed
Remove the requirement for .git to be a directory.
This is achieved by somewhat costly, but still cost-minimized handling of the Git repository itself.
1 parent 4e03952 commit a7c1211

File tree

54 files changed

+202
-148
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+202
-148
lines changed

crates/but-api/src/commands/claude.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,11 @@ pub async fn claude_get_session_details(
7272
let session_id = uuid::Uuid::parse_str(&session_id).map_err(anyhow::Error::from)?;
7373
let session = but_claude::db::get_session_by_id(&mut ctx, session_id)?
7474
.context("Could not find session")?;
75-
let current_id = Transcript::current_valid_session_id(&project.path, &session).await?;
75+
let current_id =
76+
Transcript::current_valid_session_id(&project.worktree_dir(), &session).await?;
7677
if let Some(current_id) = current_id {
7778
let transcript_path =
78-
but_claude::Transcript::get_transcript_path(&project.path, current_id)?;
79+
but_claude::Transcript::get_transcript_path(&project.worktree_dir(), current_id)?;
7980
let transcript = but_claude::Transcript::from_file(&transcript_path)?;
8081
Ok(but_claude::ClaudeSessionDetails {
8182
summary: transcript.summary(),
@@ -204,8 +205,8 @@ pub fn claude_maybe_create_prompt_dir(project_id: ProjectId, path: String) -> Re
204205
#[instrument(err(Debug))]
205206
pub async fn claude_get_mcp_config(project_id: ProjectId) -> Result<McpConfig, Error> {
206207
let project = gitbutler_project::get(project_id)?;
207-
let settings = ClaudeSettings::open(&project.path).await;
208-
let mcp_config = ClaudeMcpConfig::open(&settings, &project.path).await;
208+
let settings = ClaudeSettings::open(&project.worktree_dir()).await;
209+
let mcp_config = ClaudeMcpConfig::open(&settings, &project.worktree_dir()).await;
209210
Ok(mcp_config.mcp_servers())
210211
}
211212

@@ -215,7 +216,8 @@ pub async fn claude_get_sub_agents(
215216
project_id: ProjectId,
216217
) -> Result<Vec<but_claude::SubAgent>, Error> {
217218
let project = gitbutler_project::get(project_id)?;
218-
let sub_agents = but_claude::claude_sub_agents::read_claude_sub_agents(&project.path).await;
219+
let sub_agents =
220+
but_claude::claude_sub_agents::read_claude_sub_agents(&project.worktree_dir()).await;
219221
Ok(sub_agents)
220222
}
221223

@@ -229,7 +231,7 @@ pub async fn claude_verify_path(project_id: ProjectId, path: String) -> Result<b
229231
std::path::PathBuf::from(&path)
230232
} else {
231233
// If relative, make it relative to project path
232-
project.path.join(&path)
234+
project.worktree_dir().join(&path)
233235
};
234236

235237
// Check if the path exists and is a directory

crates/but-api/src/commands/config.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::error::Error;
1212
#[cfg_attr(feature = "tauri", tauri::command(async))]
1313
#[instrument(err(Debug))]
1414
pub fn get_gb_config(project_id: ProjectId) -> Result<GitConfigSettings, Error> {
15-
but_core::open_repo(gitbutler_project::get(project_id)?.path)?
15+
but_core::open_repo(gitbutler_project::get(project_id)?.worktree_dir())?
1616
.git_settings()
1717
.map(Into::into)
1818
.map_err(Into::into)
@@ -22,7 +22,7 @@ pub fn get_gb_config(project_id: ProjectId) -> Result<GitConfigSettings, Error>
2222
#[cfg_attr(feature = "tauri", tauri::command(async))]
2323
#[instrument(err(Debug))]
2424
pub fn set_gb_config(project_id: ProjectId, config: GitConfigSettings) -> Result<(), Error> {
25-
but_core::open_repo(gitbutler_project::get(project_id)?.path)?
25+
but_core::open_repo(gitbutler_project::get(project_id)?.worktree_dir())?
2626
.set_git_settings(&config.into())
2727
.map_err(Into::into)
2828
}
@@ -35,7 +35,7 @@ pub fn store_author_globally_if_unset(
3535
name: String,
3636
email: String,
3737
) -> Result<(), Error> {
38-
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.path)?;
38+
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.worktree_dir())?;
3939
but_rebase::commit::save_author_if_unset_in_repo(
4040
&repo,
4141
gix::config::Source::User,
@@ -61,7 +61,7 @@ pub struct AuthorInfo {
6161
#[instrument(err(Debug))]
6262
/// Return the Git author information as the project repository would see it.
6363
pub fn get_author_info(project_id: ProjectId) -> Result<AuthorInfo, Error> {
64-
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.path)?;
64+
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.worktree_dir())?;
6565
let (name, email) = repo
6666
.author()
6767
.transpose()

crates/but-api/src/commands/diff.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ pub fn tree_change_diffs(
3232
let change: but_core::TreeChange = change.into();
3333
let project = gitbutler_project::get(project_id)?;
3434
let app_settings = AppSettings::load_from_default_path_creating()?;
35-
let repo = gix::open(project.path).map_err(anyhow::Error::from)?;
35+
let repo = gix::open(project.worktree_dir()).map_err(anyhow::Error::from)?;
3636
Ok(change.unified_diff(&repo, app_settings.context_lines)?)
3737
}
3838

@@ -53,7 +53,7 @@ pub fn commit_details(
5353
commit_id: HexHash,
5454
) -> anyhow::Result<CommitDetails, Error> {
5555
let project = gitbutler_project::get(project_id)?;
56-
let repo = &gix::open(&project.path).context("Failed to open repo")?;
56+
let repo = &gix::open(project.worktree_dir()).context("Failed to open repo")?;
5757
let commit = repo
5858
.find_commit(commit_id)
5959
.context("Failed for find commit")?;
@@ -121,7 +121,7 @@ pub fn changes_in_worktree(project_id: ProjectId) -> anyhow::Result<WorktreeChan
121121

122122
let dependencies = hunk_dependencies_for_workspace_changes_by_worktree_dir(
123123
ctx,
124-
&ctx.project().path,
124+
&ctx.project().worktree_dir(),
125125
&ctx.project().gb_dir(),
126126
Some(changes.changes.clone()),
127127
);

crates/but-api/src/commands/forge.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::error::Error;
1818
#[instrument(err(Debug))]
1919
pub fn pr_templates(project_id: ProjectId, forge: ForgeName) -> Result<Vec<String>, Error> {
2020
let project = gitbutler_project::get_validated(project_id)?;
21-
Ok(available_review_templates(&project.path, &forge))
21+
Ok(available_review_templates(&project.worktree_dir(), &forge))
2222
}
2323

2424
#[api_cmd]
@@ -39,7 +39,7 @@ pub fn pr_template(
3939
if !is_valid_review_template_path(&relative_path) {
4040
return Err(anyhow::format_err!(
4141
"Invalid review template path: {:?}",
42-
Path::join(&project.path, &relative_path)
42+
Path::join(&project.worktree_dir(), &relative_path)
4343
)
4444
.into());
4545
}

crates/but-api/src/commands/virtual_branches.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ pub fn unapply_stack(project_id: ProjectId, stack_id: StackId) -> Result<(), Err
257257
let (assignments, _) = but_hunk_assignment::assignments_with_fallback(
258258
ctx,
259259
false,
260-
Some(but_core::diff::ui::worktree_changes_by_worktree_dir(project.path)?.changes),
260+
Some(but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir())?.changes),
261261
None,
262262
)?;
263263
let assigned_diffspec = but_workspace::flatten_diff_specs(

crates/but-api/src/commands/workspace.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ pub fn amend_commit_from_worktree_changes(
329329
) -> Result<commit_engine::ui::CreateCommitOutcome, Error> {
330330
let project = gitbutler_project::get(project_id)?;
331331
let mut guard = project.exclusive_worktree_access();
332-
let repo = but_core::open_repo_for_merging(project.worktree_path())?;
332+
let repo = but_core::open_repo_for_merging(project.worktree_dir())?;
333333
let app_settings = AppSettings::load_from_default_path_creating()?;
334334
let outcome = commit_engine::create_commit_and_update_refs_with_project(
335335
&repo,
@@ -364,7 +364,7 @@ pub fn discard_worktree_changes(
364364
worktree_changes: Vec<but_workspace::DiffSpec>,
365365
) -> Result<Vec<but_workspace::DiffSpec>, Error> {
366366
let project = gitbutler_project::get(project_id)?;
367-
let repo = but_core::open_repo(project.worktree_path())?;
367+
let repo = but_core::open_repo(project.worktree_dir())?;
368368
let ctx = CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
369369
let mut guard = project.exclusive_worktree_access();
370370

crates/but-claude/src/bridge.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ impl Claudes {
253253
writer,
254254
write_stderr,
255255
session,
256-
project.path.clone(),
256+
project.worktree_dir(),
257257
ctx.clone(),
258258
user_params,
259259
summary_to_resume,

crates/but-claude/src/compact.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ pub async fn generate_summary(
234234
let app_settings = ctx.lock().await.app_settings().clone();
235235
let claude_executable = app_settings.claude.executable.clone();
236236
let session_id =
237-
Transcript::current_valid_session_id(&ctx.lock().await.project().path, session)
237+
Transcript::current_valid_session_id(&ctx.lock().await.project().worktree_dir(), session)
238238
.await?
239239
.context("Cant find current session id")?;
240240

@@ -248,7 +248,7 @@ pub async fn generate_summary(
248248
command.creation_flags(CREATE_NO_WINDOW);
249249
}
250250

251-
command.current_dir(&ctx.lock().await.project().path);
251+
command.current_dir(ctx.lock().await.project().worktree_dir());
252252
command.args(["--resume", &format!("{session_id}")]);
253253
command.arg("-p");
254254
command.arg(SUMMARY_PROMPT);

crates/but-claude/src/hooks/mod.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ pub async fn handle_stop() -> anyhow::Result<ClaudeHookOutput> {
104104
)?;
105105

106106
let changes =
107-
but_core::diff::ui::worktree_changes_by_worktree_dir(project.clone().path)?.changes;
107+
but_core::diff::ui::worktree_changes_by_worktree_dir(project.clone().worktree_dir())?
108+
.changes;
108109

109110
// This is a naive way of handling this case.
110111
// If the user simply asks a question and there are no changes, we don't need to create a stack
@@ -328,7 +329,7 @@ pub fn handle_pre_tool_call() -> anyhow::Result<ClaudeHookOutput> {
328329
.ok_or(anyhow!("No worktree found for repo"))?,
329330
)?;
330331
let relative_file_path = std::path::PathBuf::from(&input.tool_input.file_path)
331-
.strip_prefix(project.path.clone())?
332+
.strip_prefix(project.worktree_dir())?
332333
.to_string_lossy()
333334
.to_string();
334335
input.tool_input.file_path = relative_file_path;
@@ -374,7 +375,7 @@ pub fn handle_post_tool_call() -> anyhow::Result<ClaudeHookOutput> {
374375
)?;
375376

376377
let relative_file_path = std::path::PathBuf::from(&input.tool_response.file_path)
377-
.strip_prefix(project.path.clone())?
378+
.strip_prefix(project.worktree_dir())?
378379
.to_string_lossy()
379380
.to_string();
380381
input.tool_response.file_path = relative_file_path.clone();
@@ -404,7 +405,7 @@ pub fn handle_post_tool_call() -> anyhow::Result<ClaudeHookOutput> {
404405
let stack_id = get_or_create_session(defer.ctx, &session_id, stacks, vb_state)?;
405406

406407
let changes =
407-
but_core::diff::ui::worktree_changes_by_worktree_dir(project.path.clone())?.changes;
408+
but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir())?.changes;
408409
let (assignments, _assignments_error) = but_hunk_assignment::assignments_with_fallback(
409410
defer.ctx,
410411
true,

crates/but-claude/src/prompt_templates.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ pub struct PromptDir {
4242

4343
/// Fetch the directories where we look up the user provided templates.
4444
///
45-
/// We want the precidence to be Global < Project < Project Local
45+
/// We want the precedence to be Global < Project < Project Local
4646
///
47-
/// As such, items last in the array take precidence, and filters last in the
48-
/// filters list also take precidence over earlier ones.
47+
/// As such, items last in the array take precedence, and filters last in the
48+
/// filters list also take precedence over earlier ones.
4949
///
5050
/// The point of labeling these dirs is so we can also display where to find
5151
/// these directories in the frontend.
@@ -58,7 +58,7 @@ pub fn prompt_dirs(project: &Project) -> Result<Vec<PromptDir>> {
5858
},
5959
PromptDir {
6060
label: "Project".into(),
61-
path: project.path.join(".gitbutler/prompt-templates"),
61+
path: project.gb_dir().join("prompt-templates"),
6262
filters: vec![".md".into(), ".local.md".into()],
6363
},
6464
])
@@ -124,7 +124,7 @@ pub fn maybe_create_dir(project: &Project, path: &str) -> Result<()> {
124124
let path = if path.is_absolute() {
125125
path
126126
} else {
127-
&project.path.join(path)
127+
&project.worktree_dir().join(path)
128128
};
129129

130130
if path.try_exists()? {

0 commit comments

Comments
 (0)