mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-24 12:48:55 +00:00
cmd: when a single remote is defined, default to it for git fetch/push
A simple quick implementation of what I've suggested on discord
This commit is contained in:
parent
df7079033e
commit
791b821115
4 changed files with 90 additions and 15 deletions
|
@ -47,7 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
based on terminal width. [#1043](https://github.com/martinvonz/jj/issues/1043)
|
based on terminal width. [#1043](https://github.com/martinvonz/jj/issues/1043)
|
||||||
|
|
||||||
* Nodes in the (text-based) graphical log output now use a `◉` symbol instead
|
* Nodes in the (text-based) graphical log output now use a `◉` symbol instead
|
||||||
of the letter `o`. The ASCII-based graph styles still use `o`.
|
of the letter `o`. The ASCII-based graph styles still use `o`.
|
||||||
|
|
||||||
* Commands that accept a diff format (`jj diff`, `jj interdiff`, `jj show`,
|
* Commands that accept a diff format (`jj diff`, `jj interdiff`, `jj show`,
|
||||||
`jj log`, and `jj obslog`) now accept `--types` to show only the type of file
|
`jj log`, and `jj obslog`) now accept `--types` to show only the type of file
|
||||||
|
@ -77,6 +77,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
* `jj obslog` and `jj log` now show abandoned commits as hidden.
|
* `jj obslog` and `jj log` now show abandoned commits as hidden.
|
||||||
|
|
||||||
|
* `jj git fetch` and `jj git push` will now use the single defined remote even if it is not named "origin".
|
||||||
|
|
||||||
### Fixed bugs
|
### Fixed bugs
|
||||||
|
|
||||||
* Modify/delete conflicts now include context lines
|
* Modify/delete conflicts now include context lines
|
||||||
|
@ -211,7 +213,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
[the documentation](docs/config.md).
|
[the documentation](docs/config.md).
|
||||||
|
|
||||||
* `jj print` was renamed to `jj cat`. `jj print` remains as an alias.
|
* `jj print` was renamed to `jj cat`. `jj print` remains as an alias.
|
||||||
|
|
||||||
* In content that goes to the terminal, the ANSI escape byte (0x1b) is replaced
|
* In content that goes to the terminal, the ANSI escape byte (0x1b) is replaced
|
||||||
by a "␛" character. That prevents them from interfering with the ANSI escapes
|
by a "␛" character. That prevents them from interfering with the ANSI escapes
|
||||||
jj itself writes.
|
jj itself writes.
|
||||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::Mutex;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use clap::{ArgGroup, Subcommand};
|
use clap::{ArgGroup, Subcommand};
|
||||||
|
use config::ConfigError;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use jujutsu_lib::backend::ObjectId;
|
use jujutsu_lib::backend::ObjectId;
|
||||||
use jujutsu_lib::git::{self, GitFetchError, GitPushError, GitRefUpdate};
|
use jujutsu_lib::git::{self, GitFetchError, GitPushError, GitRefUpdate};
|
||||||
|
@ -292,17 +293,12 @@ fn cmd_git_fetch(
|
||||||
args: &GitFetchArgs,
|
args: &GitFetchArgs,
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let mut workspace_command = command.workspace_helper(ui)?;
|
let mut workspace_command = command.workspace_helper(ui)?;
|
||||||
|
let git_repo = get_git_repo(workspace_command.repo().store())?;
|
||||||
let remotes = if args.remotes.is_empty() {
|
let remotes = if args.remotes.is_empty() {
|
||||||
const KEY: &str = "git.fetch";
|
get_default_fetch_remotes(ui, command, &git_repo)?
|
||||||
let config = command.settings().config();
|
|
||||||
config
|
|
||||||
.get(KEY)
|
|
||||||
.or_else(|_| config.get_string(KEY).map(|r| vec![r]))?
|
|
||||||
} else {
|
} else {
|
||||||
args.remotes.clone()
|
args.remotes.clone()
|
||||||
};
|
};
|
||||||
let repo = workspace_command.repo();
|
|
||||||
let git_repo = get_git_repo(repo.store())?;
|
|
||||||
let mut tx = workspace_command.start_transaction(&format!(
|
let mut tx = workspace_command.start_transaction(&format!(
|
||||||
"fetch from git remote(s) {}",
|
"fetch from git remote(s) {}",
|
||||||
remotes.iter().join(",")
|
remotes.iter().join(",")
|
||||||
|
@ -328,6 +324,47 @@ fn cmd_git_fetch(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_single_remote(git_repo: &git2::Repository) -> Result<Option<String>, CommandError> {
|
||||||
|
let git_remotes = git_repo.remotes()?;
|
||||||
|
Ok(match git_remotes.len() {
|
||||||
|
1 => git_remotes.get(0).map(ToOwned::to_owned),
|
||||||
|
_ => None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_REMOTE: &str = "origin";
|
||||||
|
|
||||||
|
fn get_default_fetch_remotes(
|
||||||
|
ui: &mut Ui,
|
||||||
|
command: &CommandHelper,
|
||||||
|
git_repo: &git2::Repository,
|
||||||
|
) -> Result<Vec<String>, CommandError> {
|
||||||
|
const KEY: &str = "git.fetch";
|
||||||
|
let config = command.settings().config();
|
||||||
|
|
||||||
|
match config
|
||||||
|
.get(KEY)
|
||||||
|
.or_else(|_| config.get_string(KEY).map(|r| vec![r]))
|
||||||
|
{
|
||||||
|
// if nothing was explicitly configured, try to guess
|
||||||
|
Err(ConfigError::NotFound(_)) => {
|
||||||
|
if let Some(remote) = get_single_remote(git_repo)? {
|
||||||
|
if remote != DEFAULT_REMOTE {
|
||||||
|
writeln!(
|
||||||
|
ui.hint(),
|
||||||
|
"Fetching from the only existing remote: {}",
|
||||||
|
remote
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
Ok(vec![remote])
|
||||||
|
} else {
|
||||||
|
Ok(vec![DEFAULT_REMOTE.to_owned()])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r => Ok(r?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn absolute_git_source(cwd: &Path, source: &str) -> String {
|
fn absolute_git_source(cwd: &Path, source: &str) -> String {
|
||||||
// Git appears to turn URL-like source to absolute path if local git directory
|
// Git appears to turn URL-like source to absolute path if local git directory
|
||||||
// exits, and fails because '$PWD/https' is unsupported protocol. Since it would
|
// exits, and fails because '$PWD/https' is unsupported protocol. Since it would
|
||||||
|
@ -577,11 +614,14 @@ fn cmd_git_push(
|
||||||
args: &GitPushArgs,
|
args: &GitPushArgs,
|
||||||
) -> Result<(), CommandError> {
|
) -> Result<(), CommandError> {
|
||||||
let mut workspace_command = command.workspace_helper(ui)?;
|
let mut workspace_command = command.workspace_helper(ui)?;
|
||||||
|
let git_repo = get_git_repo(workspace_command.repo().store())?;
|
||||||
|
|
||||||
let remote = if let Some(name) = &args.remote {
|
let remote = if let Some(name) = &args.remote {
|
||||||
name.clone()
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
command.settings().config().get("git.push")?
|
get_default_push_remote(ui, command, &git_repo)?
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut tx;
|
let mut tx;
|
||||||
let mut branch_updates = vec![];
|
let mut branch_updates = vec![];
|
||||||
let mut seen_branches = hashset! {};
|
let mut seen_branches = hashset! {};
|
||||||
|
@ -871,7 +911,6 @@ fn cmd_git_push(
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let git_repo = get_git_repo(repo.store())?;
|
|
||||||
with_remote_callbacks(ui, |cb| {
|
with_remote_callbacks(ui, |cb| {
|
||||||
git::push_updates(&git_repo, &remote, &ref_updates, cb)
|
git::push_updates(&git_repo, &remote, &ref_updates, cb)
|
||||||
})
|
})
|
||||||
|
@ -884,6 +923,27 @@ fn cmd_git_push(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_default_push_remote(
|
||||||
|
ui: &mut Ui,
|
||||||
|
command: &CommandHelper,
|
||||||
|
git_repo: &git2::Repository,
|
||||||
|
) -> Result<String, CommandError> {
|
||||||
|
match command.settings().config().get_string("git.push") {
|
||||||
|
// similar to get_default_fetch_remotes
|
||||||
|
Err(ConfigError::NotFound(_)) => {
|
||||||
|
if let Some(remote) = get_single_remote(git_repo)? {
|
||||||
|
if remote != DEFAULT_REMOTE {
|
||||||
|
writeln!(ui.hint(), "Pushing to the only existing remote: {}", remote)?;
|
||||||
|
}
|
||||||
|
Ok(remote)
|
||||||
|
} else {
|
||||||
|
Ok(DEFAULT_REMOTE.to_owned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
r => Ok(r?),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn branch_updates_for_push(
|
fn branch_updates_for_push(
|
||||||
repo: &dyn Repo,
|
repo: &dyn Repo,
|
||||||
remote_name: &str,
|
remote_name: &str,
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
[aliases]
|
[aliases]
|
||||||
# Placeholder: added by user
|
# Placeholder: added by user
|
||||||
|
|
||||||
[git]
|
|
||||||
push = "origin"
|
|
||||||
fetch = "origin"
|
|
||||||
|
|
||||||
[revset-aliases]
|
[revset-aliases]
|
||||||
# Placeholder: added by user
|
# Placeholder: added by user
|
||||||
|
|
||||||
|
|
|
@ -88,6 +88,23 @@ fn test_git_fetch_single_remote() {
|
||||||
let repo_path = test_env.env_root().join("repo");
|
let repo_path = test_env.env_root().join("repo");
|
||||||
add_git_remote(&test_env, &repo_path, "rem1");
|
add_git_remote(&test_env, &repo_path, "rem1");
|
||||||
|
|
||||||
|
test_env
|
||||||
|
.jj_cmd(&repo_path, &["git", "fetch"])
|
||||||
|
.assert()
|
||||||
|
.success()
|
||||||
|
.stderr("Fetching from the only existing remote: rem1\n");
|
||||||
|
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
||||||
|
rem1: 6a21102783e8 message
|
||||||
|
"###);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_git_fetch_single_remote_from_arg() {
|
||||||
|
let test_env = TestEnvironment::default();
|
||||||
|
test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]);
|
||||||
|
let repo_path = test_env.env_root().join("repo");
|
||||||
|
add_git_remote(&test_env, &repo_path, "rem1");
|
||||||
|
|
||||||
test_env.jj_cmd_success(&repo_path, &["git", "fetch", "--remote", "rem1"]);
|
test_env.jj_cmd_success(&repo_path, &["git", "fetch", "--remote", "rem1"]);
|
||||||
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
||||||
rem1: 6a21102783e8 message
|
rem1: 6a21102783e8 message
|
||||||
|
|
Loading…
Reference in a new issue