From 965a8db38b7edc8fa0c8c3d302c80e56c23276e4 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 | 23 +++++++ 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, 187 insertions(+), 28 deletions(-) diff --git a/docs/config.md b/docs/config.md index f93d19afc77..4c8debf5012 100644 --- a/docs/config.md +++ b/docs/config.md @@ -268,6 +268,29 @@ the conflict is done, `jj` assumes that the conflict was only 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 Instead of `~/.jjconfig.toml`, the config settings can be located at 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 c0c5f379ce9..5256025b32f 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_style(&self) -> String { self.config .get_string("ui.graph.style") 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 7e5014ded05..1eb86312cfa 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::{ @@ -160,6 +161,7 @@ fn test_resolve_symbol_commit_id() { #[test_case(true ; "readonly")] fn test_resolve_symbol_change_id(readonly: bool) { 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; @@ -196,7 +198,7 @@ fn test_resolve_symbol_change_id(readonly: bool) { } 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(); // Test the test setup assert_eq!( diff --git a/src/cli_util.rs b/src/cli_util.rs index c8b5053f0c0..72f7d2da2da 100644 --- a/src/cli_util.rs +++ b/src/cli_util.rs @@ -505,7 +505,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 88ac66d828d..a155909524a 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..a15022631fc 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("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 {