From a9679235fdec34fc6e099a576e49cb56ce4ab28c Mon Sep 17 00:00:00 2001 From: Glen Choo Date: Mon, 12 Dec 2022 16:18:19 -0800 Subject: [PATCH] git: add git.auto-local-branch Add a new git.auto-local-branch config option. When set to false, a remote-tracking branch imported from Git will not automatically create a local branch target. This is implemented by a new GitSettings struct that passes Git-related settings from UserSettings. This behavior is particularly useful in a co-located jj and Git repo, because a Git remote might have branches that are not of everyday interest to the user, so it does not make sense to export them as local branches in Git. E.g. https://github.com/gitster/git, the maintainer's fork of Git, has 379 branches, most of which are topic branches kept around for historical reasons, and Git developers wouldn't be expected to have local branches for each remote-tracking branch. --- docs/config.md | 20 +++++++ lib/src/git.rs | 8 ++- lib/src/settings.rs | 26 ++++++++ lib/tests/test_git.rs | 102 ++++++++++++++++++++++++++------ lib/tests/test_revset.rs | 4 +- src/cli_util.rs | 2 +- src/commands/git.rs | 24 ++++++-- src/commands/mod.rs | 6 +- tests/test_git_import_export.rs | 20 +++++++ 9 files changed, 184 insertions(+), 28 deletions(-) diff --git a/docs/config.md b/docs/config.md index bab3d8f1fba..229675fbe92 100644 --- a/docs/config.md +++ b/docs/config.md @@ -188,8 +188,28 @@ partially resolved and parses the conflict markers to get the new state of the conflict. The conflict is considered fully resolved when there are no conflict markers left. +## Git settings +### Automatic local branch creation +By default, when `jj` imports a remote-tracking branch from Git, it also +creates a local branch with the same name. In some repositories, this +may be undesirable, e.g.: + +- There is a remote with a lot of historical branches that you don't + want to be exported to the co-located Git repo. +- There are multiple remotes with conflicting views of that branch, + resulting in an unhelpful conflicted state. + +You can disable this behavior by setting `git.auto-local-branch` like +so, + + git.auto-local-branch = false + +Note that this setting may make it easier to accidentally delete remote +branches. Since the local branch isn't created, the remote branch will be +deleted if you push the branch with `jj git push --branch` or `jj git push +--all`. # Alternative ways to specify configuration settings diff --git a/lib/src/git.rs b/lib/src/git.rs index 184c003c088..22c2ad99a3f 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -25,6 +25,7 @@ use crate::commit::Commit; use crate::git_backend::NO_GC_REF_NAMESPACE; use crate::op_store::RefTarget; use crate::repo::MutableRepo; +use crate::settings::GitSettings; use crate::view::RefName; #[derive(Error, Debug, PartialEq)] @@ -65,6 +66,7 @@ fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) { pub fn import_refs( mut_repo: &mut MutableRepo, git_repo: &git2::Repository, + git_settings: &GitSettings, ) -> Result<(), GitImportError> { let store = mut_repo.store().clone(); let mut existing_git_refs = mut_repo.view().git_refs().clone(); @@ -141,6 +143,9 @@ pub fn import_refs( mut_repo.merge_single_ref(&ref_name, old_git_target.as_ref(), new_git_target.as_ref()); // If a git remote-tracking branch changed, apply the change to the local branch // as well + if !git_settings.auto_local_branch { + continue; + } if let RefName::RemoteBranch { branch, remote: _ } = ref_name { mut_repo.merge_single_ref( &RefName::LocalBranch(branch), @@ -336,6 +341,7 @@ pub fn fetch( git_repo: &git2::Repository, remote_name: &str, callbacks: RemoteCallbacks<'_>, + git_settings: &GitSettings, ) -> Result, GitFetchError> { let mut remote = git_repo @@ -378,7 +384,7 @@ pub fn fetch( tracing::debug!("remote.disconnect"); remote.disconnect()?; tracing::debug!("import_refs"); - import_refs(mut_repo, git_repo).map_err(|err| match err { + import_refs(mut_repo, git_repo, git_settings).map_err(|err| match err { GitImportError::InternalGitError(source) => GitFetchError::InternalGitError(source), })?; Ok(default_branch) diff --git a/lib/src/settings.rs b/lib/src/settings.rs index 348f2f293af..2a0ed1e9384 100644 --- a/lib/src/settings.rs +++ b/lib/src/settings.rs @@ -33,6 +33,28 @@ pub struct RepoSettings { _config: config::Config, } +#[derive(Debug, Clone)] +pub struct GitSettings { + pub auto_local_branch: bool, +} + +impl GitSettings { + pub fn from_config(config: &config::Config) -> Self { + let mut settings = GitSettings::default(); + + settings.auto_local_branch = config.get_bool("git.auto-local-branch").unwrap_or(true); + settings + } +} + +impl Default for GitSettings { + fn default() -> Self { + GitSettings { + auto_local_branch: true, + } + } +} + fn get_timestamp_config(config: &config::Config, key: &str) -> Option { match config.get_string(key) { Ok(timestamp_str) => match DateTime::parse_from_rfc3339(×tamp_str) { @@ -153,6 +175,10 @@ impl UserSettings { &self.config } + pub fn git_settings(&self) -> GitSettings { + GitSettings::from_config(&self.config) + } + pub fn graph_format(&self) -> String { self.config .get_string("ui.graph.format") diff --git a/lib/tests/test_git.rs b/lib/tests/test_git.rs index dda2228ed03..9189dacdcdf 100644 --- a/lib/tests/test_git.rs +++ b/lib/tests/test_git.rs @@ -24,7 +24,7 @@ use jujutsu_lib::git::{GitFetchError, GitPushError, GitRefUpdate}; use jujutsu_lib::git_backend::GitBackend; use jujutsu_lib::op_store::{BranchTarget, RefTarget}; use jujutsu_lib::repo::ReadonlyRepo; -use jujutsu_lib::settings::UserSettings; +use jujutsu_lib::settings::{GitSettings, UserSettings}; use maplit::{btreemap, hashset}; use tempfile::TempDir; use testutils::{create_random_commit, write_random_commit, TestRepo}; @@ -61,6 +61,7 @@ fn git_id(commit: &Commit) -> Oid { #[test] fn test_import_refs() { let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); let test_repo = TestRepo::init(true); let repo = &test_repo.repo; let git_repo = repo.store().git_repo().unwrap(); @@ -80,7 +81,7 @@ fn test_import_refs() { let git_repo = repo.store().git_repo().unwrap(); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); let repo = tx.commit(); let view = repo.view(); @@ -166,6 +167,7 @@ fn test_import_refs() { #[test] fn test_import_refs_reimport() { let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); let test_workspace = TestRepo::init(true); let repo = &test_workspace.repo; let git_repo = repo.store().git_repo().unwrap(); @@ -181,7 +183,7 @@ fn test_import_refs_reimport() { .unwrap(); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); let repo = tx.commit(); @@ -203,7 +205,7 @@ fn test_import_refs_reimport() { let repo = tx.commit(); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); let repo = tx.commit(); @@ -261,13 +263,14 @@ fn test_import_refs_reimport() { fn test_import_refs_reimport_head_removed() { // Test that re-importing refs doesn't cause a deleted head to come back let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); let test_repo = TestRepo::init(true); let repo = &test_repo.repo; let git_repo = repo.store().git_repo().unwrap(); let commit = empty_git_commit(&git_repo, "refs/heads/main", &[]); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); let commit_id = jj_id(&commit); // Test the setup @@ -275,7 +278,7 @@ fn test_import_refs_reimport_head_removed() { // Remove the head and re-import tx.mut_repo().remove_head(&commit_id); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); assert!(!tx.mut_repo().view().heads().contains(&commit_id)); } @@ -285,6 +288,7 @@ fn test_import_refs_reimport_git_head_counts() { // Test that if a branch is removed but the Git HEAD points to the commit (or a // descendant of it), we still keep it alive. let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); let test_repo = TestRepo::init(true); let repo = &test_repo.repo; let git_repo = repo.store().git_repo().unwrap(); @@ -293,7 +297,7 @@ fn test_import_refs_reimport_git_head_counts() { git_repo.set_head_detached(commit.id()).unwrap(); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); // Delete the branch and re-import. The commit should still be there since HEAD @@ -303,7 +307,7 @@ fn test_import_refs_reimport_git_head_counts() { .unwrap() .delete() .unwrap(); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); assert!(tx.mut_repo().view().heads().contains(&jj_id(&commit))); } @@ -313,13 +317,14 @@ fn test_import_refs_reimport_all_from_root_removed() { // Test that if a chain of commits all the way from the root gets unreferenced, // we abandon the whole stack, but not including the root commit. let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); let test_repo = TestRepo::init(true); let repo = &test_repo.repo; let git_repo = repo.store().git_repo().unwrap(); let commit = empty_git_commit(&git_repo, "refs/heads/main", &[]); let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); // Test the setup assert!(tx.mut_repo().view().heads().contains(&jj_id(&commit))); @@ -330,7 +335,7 @@ fn test_import_refs_reimport_all_from_root_removed() { .unwrap() .delete() .unwrap(); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); tx.mut_repo().rebase_descendants(&settings).unwrap(); assert!(!tx.mut_repo().view().heads().contains(&jj_id(&commit))); } @@ -383,11 +388,12 @@ impl GitRepoData { #[test] fn test_import_refs_empty_git_repo() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let heads_before = test_data.repo.view().heads().clone(); let mut tx = test_data .repo .start_transaction(&test_data.settings, "test"); - git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &test_data.git_repo, &git_settings).unwrap(); tx.mut_repo() .rebase_descendants(&test_data.settings) .unwrap(); @@ -402,6 +408,7 @@ fn test_import_refs_empty_git_repo() { #[test] fn test_import_refs_detached_head() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let commit1 = empty_git_commit(&test_data.git_repo, "refs/heads/main", &[]); // Delete the reference. Check that the detached HEAD commit still gets added to // the set of heads @@ -416,7 +423,7 @@ fn test_import_refs_detached_head() { let mut tx = test_data .repo .start_transaction(&test_data.settings, "test"); - git::import_refs(tx.mut_repo(), &test_data.git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &test_data.git_repo, &git_settings).unwrap(); tx.mut_repo() .rebase_descendants(&test_data.settings) .unwrap(); @@ -433,6 +440,7 @@ fn test_export_refs_no_detach() { // When exporting the branch that's current checked out, don't detach HEAD if // the target already matches let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let git_repo = test_data.git_repo; let commit1 = empty_git_commit(&git_repo, "refs/heads/main", &[]); git_repo.set_head("refs/heads/main").unwrap(); @@ -440,7 +448,7 @@ fn test_export_refs_no_detach() { .repo .start_transaction(&test_data.settings, "test"); let mut_repo = tx.mut_repo(); - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); mut_repo.rebase_descendants(&test_data.settings).unwrap(); // Do an initial export to make sure `main` is considered @@ -460,6 +468,7 @@ fn test_export_refs_no_detach() { fn test_export_refs_branch_changed() { // We can export a change to a branch let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let git_repo = test_data.git_repo; let commit = empty_git_commit(&git_repo, "refs/heads/main", &[]); git_repo @@ -471,7 +480,7 @@ fn test_export_refs_branch_changed() { .repo .start_transaction(&test_data.settings, "test"); let mut_repo = tx.mut_repo(); - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); mut_repo.rebase_descendants(&test_data.settings).unwrap(); assert_eq!(git::export_refs(mut_repo, &git_repo), Ok(vec![])); @@ -505,6 +514,7 @@ fn test_export_refs_branch_changed() { fn test_export_refs_current_branch_changed() { // If we update a branch that is checked out in the git repo, HEAD gets detached let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let git_repo = test_data.git_repo; let commit1 = empty_git_commit(&git_repo, "refs/heads/main", &[]); git_repo.set_head("refs/heads/main").unwrap(); @@ -512,7 +522,7 @@ fn test_export_refs_current_branch_changed() { .repo .start_transaction(&test_data.settings, "test"); let mut_repo = tx.mut_repo(); - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); mut_repo.rebase_descendants(&test_data.settings).unwrap(); assert_eq!(git::export_refs(mut_repo, &git_repo), Ok(vec![])); @@ -545,13 +555,14 @@ fn test_export_refs_current_branch_changed() { fn test_export_refs_unborn_git_branch() { // Can export to an empty Git repo (we can handle Git's "unborn branch" state) let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let git_repo = test_data.git_repo; git_repo.set_head("refs/heads/main").unwrap(); let mut tx = test_data .repo .start_transaction(&test_data.settings, "test"); let mut_repo = tx.mut_repo(); - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); mut_repo.rebase_descendants(&test_data.settings).unwrap(); assert_eq!(git::export_refs(mut_repo, &git_repo), Ok(vec![])); @@ -586,6 +597,7 @@ fn test_export_import_sequence() { // modify it in git to point to C, then import it again. There should be no // conflict. let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let git_repo = test_data.git_repo; let mut tx = test_data .repo @@ -599,7 +611,7 @@ fn test_export_import_sequence() { git_repo .reference("refs/heads/main", git_id(&commit_a), true, "test") .unwrap(); - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); assert_eq!( mut_repo.get_git_ref("refs/heads/main"), Some(RefTarget::Normal(commit_a.id().clone())) @@ -621,7 +633,7 @@ fn test_export_import_sequence() { .unwrap(); // Import from git - git::import_refs(mut_repo, &git_repo).unwrap(); + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); assert_eq!( mut_repo.get_git_ref("refs/heads/main"), Some(RefTarget::Normal(commit_c.id().clone())) @@ -632,6 +644,44 @@ fn test_export_import_sequence() { ); } +#[test] +fn test_import_export_no_auto_local_branch() { + // Import a remote tracking branch and export it. We should not create a git + // branch. + let test_data = GitRepoData::create(); + let git_settings = GitSettings { + auto_local_branch: false, + }; + let git_repo = test_data.git_repo; + let git_commit = empty_git_commit(&git_repo, "refs/remotes/origin/main", &[]); + + let mut tx = test_data + .repo + .start_transaction(&test_data.settings, "test"); + let mut_repo = tx.mut_repo(); + + git::import_refs(mut_repo, &git_repo, &git_settings).unwrap(); + + let expected_branch = BranchTarget { + local_target: None, + remote_targets: btreemap! { + "origin".to_string() => RefTarget::Normal(jj_id(&git_commit)) + }, + }; + assert_eq!( + mut_repo.view().branches().get("main"), + Some(expected_branch).as_ref() + ); + assert_eq!( + mut_repo.get_git_ref("refs/remotes/origin/main"), + Some(RefTarget::Normal(jj_id(&git_commit))) + ); + + // Export the branch to git + assert_eq!(git::export_refs(mut_repo, &git_repo), Ok(vec![])); + assert_eq!(mut_repo.get_git_ref("refs/heads/main"), None); +} + #[test] fn test_export_conflicts() { // We skip export of conflicted branches @@ -895,6 +945,7 @@ fn test_init() { #[test] fn test_fetch_empty_repo() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let mut tx = test_data .repo @@ -904,6 +955,7 @@ fn test_fetch_empty_repo() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); // No default branch and no refs @@ -915,6 +967,7 @@ fn test_fetch_empty_repo() { #[test] fn test_fetch_initial_commit() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let initial_git_commit = empty_git_commit(&test_data.origin_repo, "refs/heads/main", &[]); let mut tx = test_data @@ -925,6 +978,7 @@ fn test_fetch_initial_commit() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); // No default branch because the origin repo's HEAD wasn't set @@ -954,6 +1008,7 @@ fn test_fetch_initial_commit() { #[test] fn test_fetch_success() { let mut test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let initial_git_commit = empty_git_commit(&test_data.origin_repo, "refs/heads/main", &[]); let mut tx = test_data @@ -964,6 +1019,7 @@ fn test_fetch_success() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); test_data.repo = tx.commit(); @@ -983,6 +1039,7 @@ fn test_fetch_success() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); // The default branch is "main" @@ -1012,6 +1069,7 @@ fn test_fetch_success() { #[test] fn test_fetch_prune_deleted_ref() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); empty_git_commit(&test_data.git_repo, "refs/heads/main", &[]); let mut tx = test_data @@ -1022,6 +1080,7 @@ fn test_fetch_prune_deleted_ref() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); // Test the setup @@ -1039,6 +1098,7 @@ fn test_fetch_prune_deleted_ref() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); assert!(tx.mut_repo().get_branch("main").is_none()); @@ -1047,6 +1107,7 @@ fn test_fetch_prune_deleted_ref() { #[test] fn test_fetch_no_default_branch() { let test_data = GitRepoData::create(); + let git_settings = GitSettings::default(); let initial_git_commit = empty_git_commit(&test_data.origin_repo, "refs/heads/main", &[]); let mut tx = test_data @@ -1057,6 +1118,7 @@ fn test_fetch_no_default_branch() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); @@ -1078,6 +1140,7 @@ fn test_fetch_no_default_branch() { &test_data.git_repo, "origin", git::RemoteCallbacks::default(), + &git_settings, ) .unwrap(); // There is no default branch @@ -1087,7 +1150,7 @@ fn test_fetch_no_default_branch() { #[test] fn test_fetch_no_such_remote() { let test_data = GitRepoData::create(); - + let git_settings = GitSettings::default(); let mut tx = test_data .repo .start_transaction(&test_data.settings, "test"); @@ -1096,6 +1159,7 @@ fn test_fetch_no_such_remote() { &test_data.git_repo, "invalid-remote", git::RemoteCallbacks::default(), + &git_settings, ); assert!(matches!(result, Err(GitFetchError::NoSuchRemote(_)))); } diff --git a/lib/tests/test_revset.rs b/lib/tests/test_revset.rs index c8d0c97c445..737f25ef8c9 100644 --- a/lib/tests/test_revset.rs +++ b/lib/tests/test_revset.rs @@ -25,6 +25,7 @@ use jujutsu_lib::revset::{ self, optimize, parse, resolve_symbol, RevsetAliasesMap, RevsetError, RevsetExpression, RevsetWorkspaceContext, }; +use jujutsu_lib::settings::GitSettings; use jujutsu_lib::workspace::Workspace; use test_case::test_case; use testutils::{ @@ -159,6 +160,7 @@ fn test_resolve_symbol_commit_id() { #[test] fn test_resolve_symbol_change_id() { let settings = testutils::user_settings(); + let git_settings = GitSettings::default(); // Test only with git so we can get predictable change ids let test_repo = TestRepo::init(true); let repo = &test_repo.repo; @@ -195,7 +197,7 @@ fn test_resolve_symbol_change_id() { } let mut tx = repo.start_transaction(&settings, "test"); - git::import_refs(tx.mut_repo(), &git_repo).unwrap(); + git::import_refs(tx.mut_repo(), &git_repo, &git_settings).unwrap(); let repo = tx.commit(); // Test the test setup diff --git a/src/cli_util.rs b/src/cli_util.rs index 9d4b7b521a2..cc092401933 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -506,7 +506,7 @@ impl WorkspaceCommandHelper { git_repo: &Repository, ) -> Result<(), CommandError> { let mut tx = self.start_transaction("import git refs").into_inner(); - git::import_refs(tx.mut_repo(), git_repo)?; + git::import_refs(tx.mut_repo(), git_repo, &self.settings.git_settings())?; if tx.mut_repo().has_changes() { let old_git_head = self.repo.view().git_head(); let new_git_head = tx.mut_repo().view().git_head(); diff --git a/src/commands/git.rs b/src/commands/git.rs index a998d5b264c..f4be0ddcffe 100644 --- a/src/commands/git.rs +++ b/src/commands/git.rs @@ -246,8 +246,16 @@ fn cmd_git_fetch( let repo = workspace_command.repo(); let git_repo = get_git_repo(repo.store())?; let mut tx = workspace_command.start_transaction(&format!("fetch from git remote {}", &remote)); - with_remote_callbacks(ui, |cb| git::fetch(tx.mut_repo(), &git_repo, &remote, cb)) - .map_err(|err| user_error(err.to_string()))?; + with_remote_callbacks(ui, |cb| { + git::fetch( + tx.mut_repo(), + &git_repo, + &remote, + cb, + &command.settings().git_settings(), + ) + }) + .map_err(|err| user_error(err.to_string()))?; tx.finish(ui)?; Ok(()) } @@ -365,7 +373,13 @@ fn do_git_clone( let mut fetch_tx = workspace_command.start_transaction("fetch from git remote into empty repo"); let maybe_default_branch = with_remote_callbacks(ui, |cb| { - git::fetch(fetch_tx.mut_repo(), &git_repo, remote_name, cb) + git::fetch( + fetch_tx.mut_repo(), + &git_repo, + remote_name, + cb, + &command.settings().git_settings(), + ) }) .map_err(|err| match err { GitFetchError::NoSuchRemote(_) => { @@ -792,7 +806,7 @@ fn cmd_git_push( git::push_updates(&git_repo, &remote, &ref_updates, cb) }) .map_err(|err| user_error(err.to_string()))?; - git::import_refs(tx.mut_repo(), &git_repo)?; + git::import_refs(tx.mut_repo(), &git_repo, &command.settings().git_settings())?; tx.finish(ui)?; Ok(()) } @@ -828,7 +842,7 @@ fn cmd_git_import( let repo = workspace_command.repo(); let git_repo = get_git_repo(repo.store())?; let mut tx = workspace_command.start_transaction("import git refs"); - git::import_refs(tx.mut_repo(), &git_repo)?; + git::import_refs(tx.mut_repo(), &git_repo, &command.settings().git_settings())?; tx.finish(ui)?; Ok(()) } diff --git a/src/commands/mod.rs b/src/commands/mod.rs index 7c63cfe5050..a82571421f4 100644 --- a/src/commands/mod.rs +++ b/src/commands/mod.rs @@ -980,7 +980,11 @@ fn cmd_init(ui: &mut Ui, command: &CommandHelper, args: &InitArgs) -> Result<(), add_to_git_exclude(ui, &git_repo)?; } else { let mut tx = workspace_command.start_transaction("import git refs"); - jujutsu_lib::git::import_refs(tx.mut_repo(), &git_repo)?; + jujutsu_lib::git::import_refs( + tx.mut_repo(), + &git_repo, + &command.settings().git_settings(), + )?; if let Some(git_head_id) = tx.mut_repo().view().git_head() { let git_head_commit = tx.mut_repo().store().get_commit(&git_head_id)?; tx.check_out(&git_head_commit)?; diff --git a/tests/test_git_import_export.rs b/tests/test_git_import_export.rs index 927ab1c1dad..7e0f36bdb01 100644 --- a/tests/test_git_import_export.rs +++ b/tests/test_git_import_export.rs @@ -62,6 +62,7 @@ fn test_git_import_remote_only_branch() { &["git", "remote", "add", "origin", "../git-repo"], ); + // Import using default config git_repo .commit( Some("refs/heads/feature1"), @@ -76,6 +77,25 @@ fn test_git_import_remote_only_branch() { insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###" feature1: 9f01a0e04879 message "###); + + // Import using git.auto_local_branch = false + git_repo + .commit( + Some("refs/heads/feature2"), + &signature, + &signature, + "message", + &tree, + &[], + ) + .unwrap(); + test_env.add_config(b"git.auto-local-branch = false"); + test_env.jj_cmd_success(&repo_path, &["git", "fetch", "--remote=origin"]); + insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###" + feature1: 9f01a0e04879 message + feature2 (deleted) + @origin: 9f01a0e04879 message + "###); } fn get_branch_output(test_env: &TestEnvironment, repo_path: &Path) -> String {