git: Add base branch support to create_branch (#42151)

Closes [#41674](https://github.com/zed-industries/zed/issues/41674)

Description:
Creating a branch from a base requires switching to the base branch
first, then creating the new branch and checking out to it, which
requires multiple operations.

Add base_branch parameter to create_branch to allow a new branch from a
base branch in one operation which is synonymous to the command `git
switch -c <new-branch> <base-branch>`.

Below is the video after solving the issue: 

(`master` branch is the default branch here, and I create a branch
`new-branch-2` based off the `master` branch. I also show the error
which used to appear before the fix.)

[Screencast from 2025-11-07
05-14-32.webm](https://github.com/user-attachments/assets/d37d1b58-af5f-44e8-b867-2aa5d4ef3d90)

Release Notes:

- Fixed the branch-picking error by replacing multiple sequential switch
operations with just one switch operation.

Signed-off-by: ayu-ch <ayu.chandekar@gmail.com>
This commit is contained in:
Ayush Chandekar
2025-11-09 21:35:29 -05:00
committed by GitHub
parent c60d31a726
commit e025ee6a11
7 changed files with 60 additions and 43 deletions
+22 -7
View File
@@ -431,7 +431,8 @@ pub trait GitRepository: Send + Sync {
fn branches(&self) -> BoxFuture<'_, Result<Vec<Branch>>>;
fn change_branch(&self, name: String) -> BoxFuture<'_, Result<()>>;
fn create_branch(&self, name: String) -> BoxFuture<'_, Result<()>>;
fn create_branch(&self, name: String, base_branch: Option<String>)
-> BoxFuture<'_, Result<()>>;
fn rename_branch(&self, branch: String, new_name: String) -> BoxFuture<'_, Result<()>>;
fn worktrees(&self) -> BoxFuture<'_, Result<Vec<Worktree>>>;
@@ -1358,14 +1359,28 @@ impl GitRepository for RealGitRepository {
.boxed()
}
fn create_branch(&self, name: String) -> BoxFuture<'_, Result<()>> {
let repo = self.repository.clone();
fn create_branch(
&self,
name: String,
base_branch: Option<String>,
) -> BoxFuture<'_, Result<()>> {
let git_binary_path = self.any_git_binary_path.clone();
let working_directory = self.working_directory();
let executor = self.executor.clone();
self.executor
.spawn(async move {
let repo = repo.lock();
let current_commit = repo.head()?.peel_to_commit()?;
repo.branch(&name, &current_commit, false)?;
Ok(())
let mut args = vec!["switch", "-c", &name];
let base_branch_str;
if let Some(ref base) = base_branch {
base_branch_str = base.clone();
args.push(&base_branch_str);
}
GitBinary::new(git_binary_path, working_directory?, executor)
.run(&args)
.await?;
anyhow::Ok(())
})
.boxed()
}