Skip to content

Commit

Permalink
cmd: when a single remote is defined, default to it for git fetch/push
Browse files Browse the repository at this point in the history
A simple quick implementation of what I've suggested on discord
  • Loading branch information
necauqua committed Apr 14, 2023
1 parent df70790 commit 791b821
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 15 deletions.
6 changes: 4 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
78 changes: 69 additions & 9 deletions src/commands/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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(",")
Expand All @@ -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
Expand Down Expand Up @@ -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! {};
Expand Down Expand Up @@ -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)
})
Expand All @@ -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,
Expand Down
4 changes: 0 additions & 4 deletions src/config/misc.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
[aliases]
# Placeholder: added by user

[git]
push = "origin"
fetch = "origin"

[revset-aliases]
# Placeholder: added by user

Expand Down
17 changes: 17 additions & 0 deletions tests/test_git_fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 791b821

Please sign in to comment.