mirror of
https://github.com/martinvonz/jj.git
synced 2024-12-01 03:45: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)
|
||||
|
||||
* 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`,
|
||||
`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 git fetch` and `jj git push` will now use the single defined remote even if it is not named "origin".
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* 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).
|
||||
|
||||
* `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
|
||||
by a "␛" character. That prevents them from interfering with the ANSI escapes
|
||||
jj itself writes.
|
||||
|
|
|
@ -7,6 +7,7 @@ use std::sync::Mutex;
|
|||
use std::time::Instant;
|
||||
|
||||
use clap::{ArgGroup, Subcommand};
|
||||
use config::ConfigError;
|
||||
use itertools::Itertools;
|
||||
use jujutsu_lib::backend::ObjectId;
|
||||
use jujutsu_lib::git::{self, GitFetchError, GitPushError, GitRefUpdate};
|
||||
|
@ -292,17 +293,12 @@ fn cmd_git_fetch(
|
|||
args: &GitFetchArgs,
|
||||
) -> Result<(), CommandError> {
|
||||
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() {
|
||||
const KEY: &str = "git.fetch";
|
||||
let config = command.settings().config();
|
||||
config
|
||||
.get(KEY)
|
||||
.or_else(|_| config.get_string(KEY).map(|r| vec![r]))?
|
||||
get_default_fetch_remotes(ui, command, &git_repo)?
|
||||
} else {
|
||||
args.remotes.clone()
|
||||
};
|
||||
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(s) {}",
|
||||
remotes.iter().join(",")
|
||||
|
@ -328,6 +324,47 @@ fn cmd_git_fetch(
|
|||
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 {
|
||||
// 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
|
||||
|
@ -577,11 +614,14 @@ fn cmd_git_push(
|
|||
args: &GitPushArgs,
|
||||
) -> Result<(), CommandError> {
|
||||
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 {
|
||||
name.clone()
|
||||
} else {
|
||||
command.settings().config().get("git.push")?
|
||||
get_default_push_remote(ui, command, &git_repo)?
|
||||
};
|
||||
|
||||
let mut tx;
|
||||
let mut branch_updates = vec![];
|
||||
let mut seen_branches = hashset! {};
|
||||
|
@ -871,7 +911,6 @@ fn cmd_git_push(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let git_repo = get_git_repo(repo.store())?;
|
||||
with_remote_callbacks(ui, |cb| {
|
||||
git::push_updates(&git_repo, &remote, &ref_updates, cb)
|
||||
})
|
||||
|
@ -884,6 +923,27 @@ fn cmd_git_push(
|
|||
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(
|
||||
repo: &dyn Repo,
|
||||
remote_name: &str,
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
[aliases]
|
||||
# Placeholder: added by user
|
||||
|
||||
[git]
|
||||
push = "origin"
|
||||
fetch = "origin"
|
||||
|
||||
[revset-aliases]
|
||||
# Placeholder: added by user
|
||||
|
||||
|
|
|
@ -88,6 +88,23 @@ fn test_git_fetch_single_remote() {
|
|||
let repo_path = test_env.env_root().join("repo");
|
||||
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"]);
|
||||
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
||||
rem1: 6a21102783e8 message
|
||||
|
|
Loading…
Reference in a new issue