Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions apps/desktop/src/lib/project/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export type Project = {
title: string;
description?: string;
path: string;
git_dir?: string;
api?: CloudProject & {
sync: boolean;
sync_code: boolean | undefined;
Expand Down
15 changes: 9 additions & 6 deletions crates/but-api/src/commands/claude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,11 @@ pub async fn claude_get_session_details(
let session_id = uuid::Uuid::parse_str(&session_id).map_err(anyhow::Error::from)?;
let session = but_claude::db::get_session_by_id(&mut ctx, session_id)?
.context("Could not find session")?;
let current_id = Transcript::current_valid_session_id(&project.path, &session).await?;
let worktree_dir = project.worktree_dir()?;
let current_id = Transcript::current_valid_session_id(worktree_dir, &session).await?;
if let Some(current_id) = current_id {
let transcript_path =
but_claude::Transcript::get_transcript_path(&project.path, current_id)?;
but_claude::Transcript::get_transcript_path(worktree_dir, current_id)?;
let transcript = but_claude::Transcript::from_file(&transcript_path)?;
Ok(but_claude::ClaudeSessionDetails {
summary: transcript.summary(),
Expand Down Expand Up @@ -204,8 +205,9 @@ pub fn claude_maybe_create_prompt_dir(project_id: ProjectId, path: String) -> Re
#[instrument(err(Debug))]
pub async fn claude_get_mcp_config(project_id: ProjectId) -> Result<McpConfig, Error> {
let project = gitbutler_project::get(project_id)?;
let settings = ClaudeSettings::open(&project.path).await;
let mcp_config = ClaudeMcpConfig::open(&settings, &project.path).await;
let worktree_dir = project.worktree_dir()?;
let settings = ClaudeSettings::open(worktree_dir).await;
let mcp_config = ClaudeMcpConfig::open(&settings, worktree_dir).await;
Ok(mcp_config.mcp_servers())
}

Expand All @@ -215,7 +217,8 @@ pub async fn claude_get_sub_agents(
project_id: ProjectId,
) -> Result<Vec<but_claude::SubAgent>, Error> {
let project = gitbutler_project::get(project_id)?;
let sub_agents = but_claude::claude_sub_agents::read_claude_sub_agents(&project.path).await;
let sub_agents =
but_claude::claude_sub_agents::read_claude_sub_agents(project.worktree_dir()?).await;
Ok(sub_agents)
}

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

// Check if the path exists and is a directory
Expand Down
10 changes: 6 additions & 4 deletions crates/but-api/src/commands/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ use crate::error::Error;
#[cfg_attr(feature = "tauri", tauri::command(async))]
#[instrument(err(Debug))]
pub fn get_gb_config(project_id: ProjectId) -> Result<GitConfigSettings, Error> {
but_core::open_repo(gitbutler_project::get(project_id)?.path)?
gitbutler_project::get(project_id)?
.open()?
.git_settings()
.map(Into::into)
.map_err(Into::into)
Expand All @@ -22,7 +23,8 @@ pub fn get_gb_config(project_id: ProjectId) -> Result<GitConfigSettings, Error>
#[cfg_attr(feature = "tauri", tauri::command(async))]
#[instrument(err(Debug))]
pub fn set_gb_config(project_id: ProjectId, config: GitConfigSettings) -> Result<(), Error> {
but_core::open_repo(gitbutler_project::get(project_id)?.path)?
gitbutler_project::get(project_id)?
.open()?
.set_git_settings(&config.into())
.map_err(Into::into)
}
Expand All @@ -35,7 +37,7 @@ pub fn store_author_globally_if_unset(
name: String,
email: String,
) -> Result<(), Error> {
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.path)?;
let repo = gitbutler_project::get(project_id)?.open()?;
but_rebase::commit::save_author_if_unset_in_repo(
&repo,
gix::config::Source::User,
Expand All @@ -61,7 +63,7 @@ pub struct AuthorInfo {
#[instrument(err(Debug))]
/// Return the Git author information as the project repository would see it.
pub fn get_author_info(project_id: ProjectId) -> Result<AuthorInfo, Error> {
let repo = but_core::open_repo(gitbutler_project::get(project_id)?.path)?;
let repo = gitbutler_project::get(project_id)?.open()?;
let (name, email) = repo
.author()
.transpose()
Expand Down
8 changes: 4 additions & 4 deletions crates/but-api/src/commands/diff.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub fn tree_change_diffs(
let change: but_core::TreeChange = change.into();
let project = gitbutler_project::get(project_id)?;
let app_settings = AppSettings::load_from_default_path_creating()?;
let repo = gix::open(project.path).map_err(anyhow::Error::from)?;
let repo = project.open()?;
Ok(change.unified_diff(&repo, app_settings.context_lines)?)
}

Expand All @@ -53,11 +53,11 @@ pub fn commit_details(
commit_id: HexHash,
) -> anyhow::Result<CommitDetails, Error> {
let project = gitbutler_project::get(project_id)?;
let repo = &gix::open(&project.path).context("Failed to open repo")?;
let repo = project.open()?;
let commit = repo
.find_commit(commit_id)
.context("Failed for find commit")?;
let changes = but_core::diff::ui::commit_changes_by_worktree_dir(repo, commit_id.into())?;
let changes = but_core::diff::ui::commit_changes_by_worktree_dir(&repo, commit_id.into())?;
let conflict_entries = Commit::from_id(commit.id())?.conflict_entries()?;
Ok(CommitDetails {
commit: commit.try_into()?,
Expand Down Expand Up @@ -121,7 +121,7 @@ pub fn changes_in_worktree(project_id: ProjectId) -> anyhow::Result<WorktreeChan

let dependencies = hunk_dependencies_for_workspace_changes_by_worktree_dir(
ctx,
&ctx.project().path,
ctx.project().worktree_dir()?,
&ctx.project().gb_dir(),
Some(changes.changes.clone()),
);
Expand Down
6 changes: 2 additions & 4 deletions crates/but-api/src/commands/forge.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
//! In place of commands.rs
use std::path::Path;

use anyhow::Context;
use but_api_macros::api_cmd;
use gitbutler_forge::{
Expand All @@ -18,7 +16,7 @@ use crate::error::Error;
#[instrument(err(Debug))]
pub fn pr_templates(project_id: ProjectId, forge: ForgeName) -> Result<Vec<String>, Error> {
let project = gitbutler_project::get_validated(project_id)?;
Ok(available_review_templates(&project.path, &forge))
Ok(available_review_templates(project.worktree_dir()?, &forge))
}

#[api_cmd]
Expand All @@ -39,7 +37,7 @@ pub fn pr_template(
if !is_valid_review_template_path(&relative_path) {
return Err(anyhow::format_err!(
"Invalid review template path: {:?}",
Path::join(&project.path, &relative_path)
project.worktree_dir()?.join(relative_path),
)
.into());
}
Expand Down
4 changes: 3 additions & 1 deletion crates/but-api/src/commands/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ pub fn git_index_size(project_id: ProjectId) -> Result<usize, Error> {
#[cfg_attr(feature = "tauri", tauri::command(async))]
#[instrument(err(Debug))]
pub fn delete_all_data() -> Result<(), Error> {
for project in gitbutler_project::list().context("failed to list projects")? {
for project in gitbutler_project::dangerously_list_without_migration()
.context("failed to list projects")?
{
gitbutler_project::delete(project.id)
.map_err(|err| err.context("failed to delete project"))?;
}
Expand Down
5 changes: 4 additions & 1 deletion crates/but-api/src/commands/virtual_branches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,10 @@ pub fn unapply_stack(project_id: ProjectId, stack_id: StackId) -> Result<(), Err
let (assignments, _) = but_hunk_assignment::assignments_with_fallback(
ctx,
false,
Some(but_core::diff::ui::worktree_changes_by_worktree_dir(project.path)?.changes),
Some(
but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir()?.into())?
.changes,
),
None,
)?;
let assigned_diffspec = but_workspace::flatten_diff_specs(
Expand Down
4 changes: 2 additions & 2 deletions crates/but-api/src/commands/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ pub fn amend_commit_from_worktree_changes(
) -> Result<commit_engine::ui::CreateCommitOutcome, Error> {
let project = gitbutler_project::get(project_id)?;
let mut guard = project.exclusive_worktree_access();
let repo = but_core::open_repo_for_merging(project.worktree_path())?;
let repo = project.open_for_merging()?;
let app_settings = AppSettings::load_from_default_path_creating()?;
let outcome = commit_engine::create_commit_and_update_refs_with_project(
&repo,
Expand Down Expand Up @@ -364,7 +364,7 @@ pub fn discard_worktree_changes(
worktree_changes: Vec<but_workspace::DiffSpec>,
) -> Result<Vec<but_workspace::DiffSpec>, Error> {
let project = gitbutler_project::get(project_id)?;
let repo = but_core::open_repo(project.worktree_path())?;
let repo = project.open()?;
let ctx = CommandContext::open(&project, AppSettings::load_from_default_path_creating()?)?;
let mut guard = project.exclusive_worktree_access();

Expand Down
2 changes: 1 addition & 1 deletion crates/but-claude/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ impl Claudes {
writer,
write_stderr,
session,
project.path.clone(),
project.worktree_dir()?.to_owned(),
ctx.clone(),
user_params,
summary_to_resume,
Expand Down
4 changes: 2 additions & 2 deletions crates/but-claude/src/compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ pub async fn generate_summary(
let app_settings = ctx.lock().await.app_settings().clone();
let claude_executable = app_settings.claude.executable.clone();
let session_id =
Transcript::current_valid_session_id(&ctx.lock().await.project().path, session)
Transcript::current_valid_session_id(ctx.lock().await.project().worktree_dir()?, session)
.await?
.context("Cant find current session id")?;

Expand All @@ -248,7 +248,7 @@ pub async fn generate_summary(
command.creation_flags(CREATE_NO_WINDOW);
}

command.current_dir(&ctx.lock().await.project().path);
command.current_dir(ctx.lock().await.project().worktree_dir()?);
command.args(["--resume", &format!("{session_id}")]);
command.arg("-p");
command.arg(SUMMARY_PROMPT);
Expand Down
13 changes: 8 additions & 5 deletions crates/but-claude/src/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ pub async fn handle_stop() -> anyhow::Result<ClaudeHookOutput> {
.ok_or(anyhow!("No worktree found for repo"))?,
)?;

let changes =
but_core::diff::ui::worktree_changes_by_worktree_dir(project.clone().path)?.changes;
let changes = but_core::diff::ui::worktree_changes_by_worktree_dir(
project.clone().worktree_dir()?.into(),
)?
.changes;

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

let relative_file_path = std::path::PathBuf::from(&input.tool_response.file_path)
.strip_prefix(project.path.clone())?
.strip_prefix(project.worktree_dir()?)?
.to_string_lossy()
.to_string();
input.tool_response.file_path = relative_file_path.clone();
Expand Down Expand Up @@ -404,7 +406,8 @@ pub fn handle_post_tool_call() -> anyhow::Result<ClaudeHookOutput> {
let stack_id = get_or_create_session(defer.ctx, &session_id, stacks, vb_state)?;

let changes =
but_core::diff::ui::worktree_changes_by_worktree_dir(project.path.clone())?.changes;
but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir()?.into())?
.changes;
let (assignments, _assignments_error) = but_hunk_assignment::assignments_with_fallback(
defer.ctx,
true,
Expand Down
10 changes: 5 additions & 5 deletions crates/but-claude/src/prompt_templates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ pub struct PromptDir {

/// Fetch the directories where we look up the user provided templates.
///
/// We want the precidence to be Global < Project < Project Local
/// We want the precedence to be Global < Project < Project Local
///
/// As such, items last in the array take precidence, and filters last in the
/// filters list also take precidence over earlier ones.
/// As such, items last in the array take precedence, and filters last in the
/// filters list also take precedence over earlier ones.
///
/// The point of labeling these dirs is so we can also display where to find
/// these directories in the frontend.
Expand All @@ -58,7 +58,7 @@ pub fn prompt_dirs(project: &Project) -> Result<Vec<PromptDir>> {
},
PromptDir {
label: "Project".into(),
path: project.path.join(".gitbutler/prompt-templates"),
path: project.gb_dir().join("prompt-templates"),
filters: vec![".md".into(), ".local.md".into()],
},
])
Expand Down Expand Up @@ -124,7 +124,7 @@ pub fn maybe_create_dir(project: &Project, path: &str) -> Result<()> {
let path = if path.is_absolute() {
path
} else {
&project.path.join(path)
&project.worktree_dir()?.join(path)
};

if path.try_exists()? {
Expand Down
6 changes: 4 additions & 2 deletions crates/but-cursor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ pub async fn handle_after_edit() -> anyhow::Result<CursorHookOutput> {
but_claude::hooks::get_or_create_session(ctx, &input.conversation_id, stacks, vb_state)?;

let changes =
but_core::diff::ui::worktree_changes_by_worktree_dir(project.path.clone())?.changes;
but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir()?.into())?
.changes;
let (assignments, _assignments_error) =
but_hunk_assignment::assignments_with_fallback(ctx, true, Some(changes.clone()), None)?;

Expand Down Expand Up @@ -186,7 +187,8 @@ pub async fn handle_stop(nightly: bool) -> anyhow::Result<CursorHookOutput> {
)?;

let changes =
but_core::diff::ui::worktree_changes_by_worktree_dir(project.clone().path)?.changes;
but_core::diff::ui::worktree_changes_by_worktree_dir(project.worktree_dir()?.into())?
.changes;

if changes.is_empty() {
return Ok(CursorHookOutput::default());
Expand Down
5 changes: 4 additions & 1 deletion crates/but-feedback/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ impl Archival {
let output_file = self
.cache_dir
.join(format!("project-{date}.zip", date = filesafe_date_time()));
create_zip_file_from_dir(project.path, output_file)
create_zip_file_from_dir(
project.worktree_dir().unwrap_or(project.git_dir()),
output_file,
)
}

/// Create an archive commit graph behind `project_id` such that it doesn't reveal PII.
Expand Down
4 changes: 2 additions & 2 deletions crates/but-hunk-assignment/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ pub fn assign(
} else {
&hunk_dependencies_for_workspace_changes_by_worktree_dir(
ctx,
&ctx.project().path,
ctx.project().worktree_dir()?,
&ctx.project().gb_dir(),
None,
)?
Expand Down Expand Up @@ -344,7 +344,7 @@ pub fn assignments_with_fallback(
} else {
&hunk_dependencies_for_workspace_changes_by_worktree_dir(
ctx,
&ctx.project().path,
ctx.project().worktree_dir()?,
&ctx.project().gb_dir(),
Some(worktree_changes.clone()),
)?
Expand Down
2 changes: 1 addition & 1 deletion crates/but-hunk-dependency/tests/hunk_dependency/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ mod util {
)?;

Ok(TestContext {
repo: gix::open_opts(&ctx.project().path, gix::open::Options::isolated())?,
repo: ctx.project().open_isolated()?,
gitbutler_dir: ctx.project().gb_dir(),
stacks_entries: stacks,
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,7 @@ mod util {
let handle = VirtualBranchesHandle::new(ctx.project().gb_dir());

Ok(TestContext {
repo: gix::open_opts(&ctx.project().path, gix::open::Options::isolated())?,
repo: ctx.project().open_isolated()?,
stacks_entries: stacks,
common_merge_base: handle.get_default_target()?.sha.to_gix(),
})
Expand Down
2 changes: 1 addition & 1 deletion crates/but-rules/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fn handle_amend(
let changes: Vec<DiffSpec> = assignments.into_iter().map(|a| a.into()).collect();
let project = ctx.project();
let mut guard = project.exclusive_worktree_access();
let repo = but_core::open_repo_for_merging(project.worktree_path())?;
let repo = project.open_for_merging()?;

let meta = VirtualBranchesTomlMetadata::from_path(
ctx.project().gb_dir().join("virtual_branches.toml"),
Expand Down
Loading
Loading