forked from mirrors/jj
Allow jj git push
to push multiple branches/changes at once
Also creates short arg `-b` for `--branch`.
This commit is contained in:
parent
63854e7b6c
commit
fad686f48c
3 changed files with 113 additions and 71 deletions
|
@ -16,6 +16,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
|
||||
* `jj log --summary --patch` now shows both summary and diff outputs.
|
||||
|
||||
* `jj git push` now accepts multiple `--branch`/`--change` arguments
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* When sharing the working copy with a Git repo, we used to forget to export
|
||||
|
@ -28,6 +30,7 @@ Thanks to the people who made this release happen!
|
|||
* Martin von Zweigbergk (@martinvonz)
|
||||
* Danny Hooper (hooper@google.com)
|
||||
* Yuya Nishihara (@yuja)
|
||||
* Ilya Grigoriev (@ilyagr)
|
||||
|
||||
## [0.6.1] - 2022-12-05
|
||||
|
||||
|
|
156
src/commands.rs
156
src/commands.rs
|
@ -919,24 +919,25 @@ struct GitCloneArgs {
|
|||
/// Push to a Git remote
|
||||
///
|
||||
/// By default, pushes any branches pointing to `@`, or `@-` if no branches
|
||||
/// point to `@`. Use `--branch` to push a specific branch. Use `--all` to push
|
||||
/// all branches. Use `--change` to generate a branch name based on a specific
|
||||
/// commit's change ID.
|
||||
/// point to `@`. Use `--branch` to push specific branches. Use `--all` to push
|
||||
/// all branches. Use `--change` to generate branch names based on the change
|
||||
/// IDs of specific commits.
|
||||
#[derive(clap::Args, Clone, Debug)]
|
||||
#[command(group(ArgGroup::new("what").args(&["branch", "all", "change"])))]
|
||||
struct GitPushArgs {
|
||||
/// The remote to push to (only named remotes are supported)
|
||||
#[arg(long, default_value = "origin")]
|
||||
remote: String,
|
||||
/// Push only this branch
|
||||
#[arg(long)]
|
||||
branch: Option<String>,
|
||||
/// Push only this branch (can be repeated)
|
||||
#[arg(long, short)]
|
||||
branch: Vec<String>,
|
||||
/// Push all branches
|
||||
#[arg(long)]
|
||||
all: bool,
|
||||
/// Push this commit by creating a branch based on its change ID
|
||||
/// Push this commit by creating a branch based on its change ID (can be
|
||||
/// repeated)
|
||||
#[arg(long)]
|
||||
change: Option<RevisionArg>,
|
||||
change: Vec<RevisionArg>,
|
||||
/// Only display what will change on the remote
|
||||
#[arg(long)]
|
||||
dry_run: bool,
|
||||
|
@ -2783,6 +2784,18 @@ fn is_fast_forward(repo: RepoRef, branch_name: &str, new_target_id: &CommitId) -
|
|||
}
|
||||
}
|
||||
|
||||
fn make_branch_term(branch_names: &[impl AsRef<str>]) -> String {
|
||||
match branch_names {
|
||||
[branch_name] => format!("branch {}", branch_name.as_ref()),
|
||||
branch_names => {
|
||||
format!(
|
||||
"branches {}",
|
||||
branch_names.iter().map(AsRef::as_ref).join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_branch(
|
||||
ui: &mut Ui,
|
||||
command: &CommandHelper,
|
||||
|
@ -2817,18 +2830,6 @@ fn cmd_branch(
|
|||
Ok(matching_branches)
|
||||
}
|
||||
|
||||
fn make_branch_term(branch_names: &[impl AsRef<str>]) -> String {
|
||||
match branch_names {
|
||||
[branch_name] => format!("branch {}", branch_name.as_ref()),
|
||||
branch_names => {
|
||||
format!(
|
||||
"branches {}",
|
||||
branch_names.iter().map(AsRef::as_ref).join(", ")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
match subcommand {
|
||||
BranchSubcommand::Create { revision, names } => {
|
||||
let branch_names: Vec<&str> = names
|
||||
|
@ -3867,61 +3868,76 @@ fn cmd_git_push(
|
|||
|
||||
let mut tx;
|
||||
let mut branch_updates = vec![];
|
||||
if let Some(branch_name) = &args.branch {
|
||||
if let Some(update) = branch_updates_for_push(
|
||||
workspace_command.repo().as_repo_ref(),
|
||||
&args.remote,
|
||||
branch_name,
|
||||
)? {
|
||||
branch_updates.push((branch_name.clone(), update));
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
"Branch {}@{} already matches {}",
|
||||
branch_name, &args.remote, branch_name
|
||||
)?;
|
||||
}
|
||||
tx = workspace_command.start_transaction(&format!(
|
||||
"push branch {branch_name} to git remote {}",
|
||||
&args.remote
|
||||
));
|
||||
} else if let Some(change_str) = &args.change {
|
||||
let commit = workspace_command.resolve_single_rev(change_str)?;
|
||||
let branch_name = format!(
|
||||
"{}{}",
|
||||
ui.settings().push_branch_prefix(),
|
||||
commit.change_id().hex()
|
||||
);
|
||||
if workspace_command
|
||||
.repo()
|
||||
.view()
|
||||
.get_local_branch(&branch_name)
|
||||
.is_none()
|
||||
{
|
||||
writeln!(
|
||||
ui,
|
||||
"Creating branch {} for revision {}",
|
||||
if !args.branch.is_empty() {
|
||||
for branch_name in &args.branch {
|
||||
if let Some(update) = branch_updates_for_push(
|
||||
workspace_command.repo().as_repo_ref(),
|
||||
&args.remote,
|
||||
branch_name,
|
||||
change_str.deref()
|
||||
)?;
|
||||
)? {
|
||||
branch_updates.push((branch_name.clone(), update));
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
"Branch {}@{} already matches {}",
|
||||
branch_name, &args.remote, branch_name
|
||||
)?;
|
||||
}
|
||||
}
|
||||
tx = workspace_command.start_transaction(&format!(
|
||||
"push change {} to git remote {}",
|
||||
commit.change_id().hex(),
|
||||
"push {} to git remote {}",
|
||||
make_branch_term(&args.branch),
|
||||
&args.remote
|
||||
));
|
||||
tx.mut_repo()
|
||||
.set_local_branch(branch_name.clone(), RefTarget::Normal(commit.id().clone()));
|
||||
if let Some(update) =
|
||||
branch_updates_for_push(tx.mut_repo().as_repo_ref(), &args.remote, &branch_name)?
|
||||
{
|
||||
branch_updates.push((branch_name.clone(), update));
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
"Branch {}@{} already matches {}",
|
||||
branch_name, &args.remote, branch_name
|
||||
)?;
|
||||
} else if !args.change.is_empty() {
|
||||
// TODO: Allow specifying --branch and --change at the same time
|
||||
let commits: Vec<_> = args
|
||||
.change
|
||||
.iter()
|
||||
.map(|change_str| workspace_command.resolve_single_rev(change_str))
|
||||
.try_collect()?;
|
||||
tx = workspace_command.start_transaction(&format!(
|
||||
"push {} {} to git remote {}",
|
||||
if commits.len() > 1 {
|
||||
"changes"
|
||||
} else {
|
||||
"change"
|
||||
},
|
||||
commits.iter().map(|c| c.change_id().hex()).join(", "),
|
||||
&args.remote
|
||||
));
|
||||
for (change_str, commit) in std::iter::zip(args.change.iter(), commits) {
|
||||
let branch_name = format!(
|
||||
"{}{}",
|
||||
ui.settings().push_branch_prefix(),
|
||||
commit.change_id().hex()
|
||||
);
|
||||
if workspace_command
|
||||
.repo()
|
||||
.view()
|
||||
.get_local_branch(&branch_name)
|
||||
.is_none()
|
||||
{
|
||||
writeln!(
|
||||
ui,
|
||||
"Creating branch {} for revision {}",
|
||||
branch_name,
|
||||
change_str.deref()
|
||||
)?;
|
||||
}
|
||||
tx.mut_repo()
|
||||
.set_local_branch(branch_name.clone(), RefTarget::Normal(commit.id().clone()));
|
||||
if let Some(update) =
|
||||
branch_updates_for_push(tx.mut_repo().as_repo_ref(), &args.remote, &branch_name)?
|
||||
{
|
||||
branch_updates.push((branch_name.clone(), update));
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
"Branch {}@{} already matches {}",
|
||||
branch_name, &args.remote, branch_name
|
||||
)?;
|
||||
}
|
||||
}
|
||||
} else if args.all {
|
||||
// TODO: Is it useful to warn about conflicted branches?
|
||||
|
|
|
@ -130,7 +130,7 @@ fn test_git_push_no_current_branch() {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_git_push_all() {
|
||||
fn test_git_push_multiple() {
|
||||
let (test_env, workspace_root) = set_up();
|
||||
test_env.jj_cmd_success(&workspace_root, &["branch", "delete", "branch1"]);
|
||||
test_env.jj_cmd_success(
|
||||
|
@ -157,6 +157,17 @@ fn test_git_push_all() {
|
|||
Add branch my-branch to afc3e612e744
|
||||
Dry-run requested, not pushing.
|
||||
"###);
|
||||
// Dry run requesting two specific branches
|
||||
let stdout = test_env.jj_cmd_success(
|
||||
&workspace_root,
|
||||
&["git", "push", "-b=branch1", "-b=my-branch", "--dry-run"],
|
||||
);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
Branch changes to push to origin:
|
||||
Delete branch branch1 from 828a683493c6
|
||||
Add branch my-branch to afc3e612e744
|
||||
Dry-run requested, not pushing.
|
||||
"###);
|
||||
let stdout = test_env.jj_cmd_success(&workspace_root, &["git", "push", "--all"]);
|
||||
insta::assert_snapshot!(stdout, @r###"
|
||||
Branch changes to push to origin:
|
||||
|
@ -191,6 +202,18 @@ fn test_git_push_changes() {
|
|||
Branch changes to push to origin:
|
||||
Add branch push-<CHANGE_ID> to ccebc2439094
|
||||
"###);
|
||||
// test pushing two changes at once
|
||||
std::fs::write(workspace_root.join("file"), "modified2").unwrap();
|
||||
let stdout = test_env.jj_cmd_success(
|
||||
&workspace_root,
|
||||
&["git", "push", "--change", "@", "--change", "@-"],
|
||||
);
|
||||
insta::assert_snapshot!(replace_changeid(&stdout), @r###"
|
||||
Creating branch push-<CHANGE_ID> for revision @-
|
||||
Branch changes to push to origin:
|
||||
Force branch push-<CHANGE_ID> from ccebc2439094 to 1624f122b2b1
|
||||
Add branch push-<CHANGE_ID> to 0a736fed65c0
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Reference in a new issue