forked from mirrors/jj
cli: add a mode of pushing with branch taken from change ID
This adds `jj git push --change <revision>` which creates a branch with a name based on the revision's change ID, and then pushes that like with `--branch`. That can be useful so you don't have to manually add the branch (and come up with a name for it). The created branch behaves like any other branch, so it's possible to make it point to a commit with a different change ID.
This commit is contained in:
parent
bc75b08f4b
commit
81a8cfefcb
3 changed files with 40 additions and 14 deletions
|
@ -62,6 +62,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
`jj git fetch` will now abandon unreferenced commits and rebase any local
|
||||
changes you had on top.
|
||||
|
||||
* `jj git push` gained a `--change <revision>` argument. When that's used, it
|
||||
will create a branch named after the revision's change ID, so you don't have
|
||||
to create a branch yourself.
|
||||
|
||||
### Fixed bugs
|
||||
|
||||
* When rebasing a conflict where one side modified a file and the other side
|
||||
|
|
|
@ -1776,6 +1776,9 @@ struct GitPushArgs {
|
|||
/// Push only this branch
|
||||
#[clap(long)]
|
||||
branch: Option<String>,
|
||||
/// Push this commit by creating a branch based on its change ID
|
||||
#[clap(long)]
|
||||
change: Option<String>,
|
||||
}
|
||||
|
||||
/// Update repo with changes made in the underlying Git repo
|
||||
|
@ -4738,12 +4741,31 @@ fn cmd_git_push(
|
|||
args: &GitPushArgs,
|
||||
) -> Result<(), CommandError> {
|
||||
let mut workspace_command = command.workspace_helper(ui)?;
|
||||
let repo = workspace_command.repo();
|
||||
let repo = workspace_command.repo().clone();
|
||||
|
||||
let mut tx = workspace_command.start_transaction("import git refs");
|
||||
let mut branch_updates = HashMap::new();
|
||||
if let Some(branch_name) = &args.branch {
|
||||
if let Some(update) = branch_updates_for_push(repo, &args.remote, branch_name)? {
|
||||
branch_updates.insert(branch_name, update);
|
||||
if let Some(update) =
|
||||
branch_updates_for_push(repo.as_repo_ref(), &args.remote, branch_name)?
|
||||
{
|
||||
branch_updates.insert(branch_name.clone(), update);
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
"Branch {}@{} already matches {}",
|
||||
branch_name, &args.remote, branch_name
|
||||
)?;
|
||||
}
|
||||
} else if let Some(change_str) = &args.change {
|
||||
let commit = workspace_command.resolve_single_rev(ui, change_str)?;
|
||||
let branch_name = format!("push-{}", commit.change_id().hex());
|
||||
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.insert(branch_name.clone(), update);
|
||||
} else {
|
||||
writeln!(
|
||||
ui,
|
||||
|
@ -4772,7 +4794,7 @@ fn cmd_git_push(
|
|||
continue;
|
||||
}
|
||||
}
|
||||
branch_updates.insert(branch_name, update);
|
||||
branch_updates.insert(branch_name.clone(), update);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4828,25 +4850,19 @@ fn cmd_git_push(
|
|||
let git_repo = get_git_repo(repo.store())?;
|
||||
git::push_updates(&git_repo, &args.remote, &ref_updates)
|
||||
.map_err(|err| CommandError::UserError(err.to_string()))?;
|
||||
let mut tx = workspace_command.start_transaction("import git refs");
|
||||
git::import_refs(tx.mut_repo(), &git_repo)?;
|
||||
workspace_command.finish_transaction(ui, tx)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn branch_updates_for_push(
|
||||
repo: &Arc<ReadonlyRepo>,
|
||||
repo: RepoRef,
|
||||
remote_name: &str,
|
||||
branch_name: &str,
|
||||
) -> Result<Option<BranchPushUpdate>, CommandError> {
|
||||
let maybe_branch_target = repo.view().get_branch(branch_name);
|
||||
if maybe_branch_target.is_none() {
|
||||
return Err(CommandError::UserError(format!(
|
||||
"Branch {} doesn't exist",
|
||||
branch_name
|
||||
)));
|
||||
}
|
||||
let branch_target = maybe_branch_target.unwrap();
|
||||
let branch_target = maybe_branch_target
|
||||
.ok_or_else(|| CommandError::UserError(format!("Branch {} doesn't exist", branch_name)))?;
|
||||
let push_action = classify_branch_push_action(branch_target, remote_name);
|
||||
|
||||
match push_action {
|
||||
|
|
|
@ -49,6 +49,12 @@ fn test_git_push() {
|
|||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: Won't push open commit
|
||||
"###);
|
||||
// When pushing with `--change`, won't push if it points to an open commit
|
||||
let stderr =
|
||||
test_env.jj_cmd_failure(&workspace_root, &["git", "push", "--change", "my-branch"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: Won't push open commit
|
||||
"###);
|
||||
|
||||
// Try pushing a conflict
|
||||
std::fs::write(workspace_root.join("file"), "first").unwrap();
|
||||
|
@ -61,6 +67,6 @@ fn test_git_push() {
|
|||
test_env.jj_cmd_success(&workspace_root, &["close", "-m", "third"]);
|
||||
let stderr = test_env.jj_cmd_failure(&workspace_root, &["git", "push"]);
|
||||
insta::assert_snapshot!(stderr, @r###"
|
||||
Error: Won't push commit 28b5642cb786 since it has conflicts
|
||||
Error: Won't push commit fcd0490f7df7 since it has conflicts
|
||||
"###);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue