mirror of
https://github.com/martinvonz/jj.git
synced 2025-05-05 15:32:49 +00:00
git: tolerate unknown git.fetch
remotes if others are available
If `git.fetch` contains remotes that are not available, we currently error even if other remotes are available. For common fork workflows with separate `upstream` and `origin` remotes (for example), this requires a user to either set both remotes in their user config and override single-remote repos or set only one in their user config and override all multi-remote repos to fetch from `upstream` (or both). This change updates fetching to only *warn* about unknown remotes **if** other remotes are available. If none of the configured remotes are available, an error is still raised as before.
This commit is contained in:
parent
92629ded4c
commit
1cdd79071e
@ -61,6 +61,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
* Added `ui.streampager.show-ruler` setting to configure whether the ruler should be
|
||||
shown when the builtin pager starts up.
|
||||
|
||||
* `jj git fetch` now warns instead of erroring for unknown `git.fetch` remotes
|
||||
if other remotes are available.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* Fixed crash on change-delete conflict resolution.
|
||||
|
@ -98,36 +98,26 @@ pub fn cmd_git_fetch(
|
||||
let all_remotes = git::get_all_remote_names(workspace_command.repo().store())?;
|
||||
|
||||
let mut matching_remotes = HashSet::new();
|
||||
let mut unmatched_patterns = Vec::new();
|
||||
for pattern in remote_patterns {
|
||||
let remotes = all_remotes
|
||||
.iter()
|
||||
.filter(|r| pattern.matches(r.as_str()))
|
||||
.collect_vec();
|
||||
if remotes.is_empty() {
|
||||
unmatched_patterns.push(pattern);
|
||||
writeln!(ui.warning_default(), "No git remotes matching '{pattern}'")?;
|
||||
} else {
|
||||
matching_remotes.extend(remotes);
|
||||
}
|
||||
}
|
||||
|
||||
match &unmatched_patterns[..] {
|
||||
[] => {} // Everything matched, all good
|
||||
[pattern] if pattern.is_exact() => {
|
||||
return Err(user_error(format!("No git remote named '{pattern}'")))
|
||||
}
|
||||
patterns => {
|
||||
return Err(user_error(format!(
|
||||
"No matching git remotes for patterns: {}",
|
||||
patterns.iter().join(", ")
|
||||
)))
|
||||
}
|
||||
if matching_remotes.is_empty() {
|
||||
return Err(user_error("No git remotes to push"));
|
||||
}
|
||||
|
||||
let remotes = all_remotes
|
||||
let remotes = matching_remotes
|
||||
.iter()
|
||||
.filter(|r| matching_remotes.contains(r))
|
||||
.map(|r| r.as_ref())
|
||||
.sorted()
|
||||
.collect_vec();
|
||||
|
||||
#[cfg(feature = "git2")]
|
||||
|
@ -322,7 +322,8 @@ fn test_git_fetch_with_glob_with_no_matching_remotes(subprocess: bool) {
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(output, @r"
|
||||
------- stderr -------
|
||||
Error: No matching git remotes for patterns: rem*
|
||||
Warning: No git remotes matching 'rem*'
|
||||
Error: No git remotes to push
|
||||
[EOF]
|
||||
[exit status: 1]
|
||||
");
|
||||
@ -386,6 +387,28 @@ fn test_git_fetch_multiple_remotes_from_config(subprocess: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]
|
||||
#[test_case(true; "spawn a git subprocess for remote calls")]
|
||||
fn test_git_fetch_no_matching_remote(subprocess: bool) {
|
||||
let test_env = TestEnvironment::default().with_git_subprocess(subprocess);
|
||||
test_env.run_jj_in(".", ["git", "init", "repo"]).success();
|
||||
let work_dir = test_env.work_dir("repo");
|
||||
|
||||
let output = work_dir.run_jj(["git", "fetch", "--remote", "rem1"]);
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(output, @r"
|
||||
------- stderr -------
|
||||
Warning: No git remotes matching 'rem1'
|
||||
Error: No git remotes to push
|
||||
[EOF]
|
||||
[exit status: 1]
|
||||
");
|
||||
}
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "git2", test_case(false; "use git2 for remote calls"))]
|
||||
#[test_case(true; "spawn a git subprocess for remote calls")]
|
||||
fn test_git_fetch_nonexistent_remote(subprocess: bool) {
|
||||
@ -398,14 +421,16 @@ fn test_git_fetch_nonexistent_remote(subprocess: bool) {
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(output, @r"
|
||||
------- stderr -------
|
||||
Error: No git remote named 'rem2'
|
||||
Warning: No git remotes matching 'rem2'
|
||||
bookmark: rem1@rem1 [new] untracked
|
||||
[EOF]
|
||||
[exit status: 1]
|
||||
");
|
||||
}
|
||||
insta::allow_duplicates! {
|
||||
// No remote should have been fetched as part of the failing transaction
|
||||
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
||||
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
||||
rem1@rem1: ppspxspk 4acd0343 message
|
||||
[EOF]
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,14 +447,16 @@ fn test_git_fetch_nonexistent_remote_from_config(subprocess: bool) {
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(output, @r"
|
||||
------- stderr -------
|
||||
Error: No git remote named 'rem2'
|
||||
Warning: No git remotes matching 'rem2'
|
||||
bookmark: rem1@rem1 [new] untracked
|
||||
[EOF]
|
||||
[exit status: 1]
|
||||
");
|
||||
}
|
||||
// No remote should have been fetched as part of the failing transaction
|
||||
insta::allow_duplicates! {
|
||||
insta::assert_snapshot!(get_bookmark_output(&work_dir), @"");
|
||||
insta::assert_snapshot!(get_bookmark_output(&work_dir), @r"
|
||||
rem1@rem1: ppspxspk 4acd0343 message
|
||||
[EOF]
|
||||
");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user