Skip to content

Commit

Permalink
git: let jj git push --change handle large revsets
Browse files Browse the repository at this point in the history
In a repo of mine I wanted to do something like the following to push all of my
leaves to the remote as backup:

    jj git push -c 'all:heads(base::) & mine() ~ empty()'

But couldn't, because `jj git push` doesn't handle large revsets, even though
it does handle multiple `-c` arguments, so I had to work out some pipe-to-xargs
command instead.

Signed-off-by: Austin Seipp <[email protected]>
  • Loading branch information
thoughtpolice committed Jun 19, 2024
1 parent 3e7ad4d commit 871b4c5
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 16 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* New command `jj branch move` let you update branches by name pattern or source
revision.

* `jj git push -c <arg>` can now accept large revsets that resolve to multiple
revisions. This means that `jj git push -c xyz -c abc` is now equivalent to
`jj git push -c 'all:(xyz | abc)'`.

### Fixed bugs

## [0.18.0] - 2024-06-05
Expand Down
16 changes: 12 additions & 4 deletions cli/src/commands/git/push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -464,15 +464,23 @@ fn update_change_branches(
branch_prefix: &str,
) -> Result<Vec<String>, CommandError> {
let mut branch_names = Vec::new();
for change_arg in changes {
let mut all_commits = Vec::new();

let workspace_command = tx.base_workspace_helper();

for change in changes {
let revs = workspace_command.resolve_some_revsets_default_single(&[change.clone()])?;
all_commits.extend(revs);
}

for commit in all_commits {
let workspace_command = tx.base_workspace_helper();
let commit = workspace_command.resolve_single_rev(change_arg)?;
let short_change_id = short_change_hash(commit.change_id());
let mut branch_name = format!("{branch_prefix}{}", commit.change_id().hex());
let view = tx.base_repo().view();
if view.get_local_branch(&branch_name).is_absent() {
// A local branch with the full change ID doesn't exist already, so use the
// short ID if it's not ambiguous (which it shouldn't be most of the time).
let short_change_id = short_change_hash(commit.change_id());
if workspace_command
.resolve_single_rev(&RevisionArg::from(short_change_id.clone()))
.is_ok()
Expand All @@ -484,7 +492,7 @@ fn update_change_branches(
if view.get_local_branch(&branch_name).is_absent() {
writeln!(
ui.status(),
"Creating branch {branch_name} for revision {change_arg}",
"Creating branch {branch_name} for revision {short_change_id}",
)?;
}
tx.mut_repo()
Expand Down
33 changes: 21 additions & 12 deletions cli/tests/test_git_push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -580,27 +580,36 @@ fn test_git_push_changes() {
let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--change", "@"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Creating branch push-yostqsxwqrlt for revision @
Creating branch push-yostqsxwqrlt for revision yostqsxwqrlt
Branch changes to push to origin:
Add branch push-yostqsxwqrlt to 28d7620ea63a
"###);
// test pushing two changes at once
std::fs::write(workspace_root.join("file"), "modified2").unwrap();
let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=@", "-c=@-"]);
let stderr = test_env.jj_cmd_failure(&workspace_root, &["git", "push", "-c=(@|@-)"]);
insta::assert_snapshot!(stderr, @r###"
Error: Revset "(@|@-)" resolved to more than one revision
Hint: The revset "(@|@-)" resolved to these revisions:
yostqsxw 48d8c794 push-yostqsxwqrlt* | bar
yqosqzyt fa16a141 foo
Hint: Prefix the expression with 'all:' to allow any number of revisions (i.e. 'all:(@|@-)').
"###);
// test pushing two changes at once, part 2
let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=all:(@|@-)"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Creating branch push-yqosqzytrlsw for revision @-
Creating branch push-yqosqzytrlsw for revision yqosqzytrlsw
Branch changes to push to origin:
Move sideways branch push-yostqsxwqrlt from 28d7620ea63a to 48d8c7948133
Add branch push-yqosqzytrlsw to fa16a14170fb
"###);
// specifying the same change twice doesn't break things
std::fs::write(workspace_root.join("file"), "modified3").unwrap();
let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=@", "-c=@"]);
let (stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "-c=all:(@|@)"]);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Branch changes to push to origin:
Move sideways branch push-yostqsxwqrlt from 48d8c7948133 to b5f030322b1d
Move sideways branch push-yostqsxwqrlt from 48d8c7948133 to 8a2941b572b9
"###);

// specifying the same branch with --change/--branch doesn't break things
Expand All @@ -612,7 +621,7 @@ fn test_git_push_changes() {
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Branch changes to push to origin:
Move sideways branch push-yostqsxwqrlt from b5f030322b1d to 4df62cec2ee4
Move sideways branch push-yostqsxwqrlt from 8a2941b572b9 to 5b65c040beef
"###);

// try again with --change that moves the branch forward
Expand All @@ -631,7 +640,7 @@ fn test_git_push_changes() {
insta::assert_snapshot!(stdout, @r###"
Working copy changes:
M file
Working copy : yostqsxw 3e2ce808 bar
Working copy : yostqsxw 361948b1 bar
Parent commit: yqosqzyt fa16a141 push-yostqsxwqrlt* push-yqosqzytrlsw | foo
"###);
let (stdout, stderr) = test_env.jj_cmd_ok(
Expand All @@ -641,13 +650,13 @@ fn test_git_push_changes() {
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Branch changes to push to origin:
Move sideways branch push-yostqsxwqrlt from 4df62cec2ee4 to 3e2ce808759b
Move sideways branch push-yostqsxwqrlt from 5b65c040beef to 361948b172e3
"###);
let stdout = test_env.jj_cmd_success(&workspace_root, &["status"]);
insta::assert_snapshot!(stdout, @r###"
Working copy changes:
M file
Working copy : yostqsxw 3e2ce808 push-yostqsxwqrlt | bar
Working copy : yostqsxw 361948b1 push-yostqsxwqrlt | bar
Parent commit: yqosqzyt fa16a141 push-yqosqzytrlsw | foo
"###);

Expand All @@ -664,9 +673,9 @@ fn test_git_push_changes() {
);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Creating branch test-yostqsxwqrlt for revision @
Creating branch test-yostqsxwqrlt for revision yostqsxwqrlt
Branch changes to push to origin:
Add branch test-yostqsxwqrlt to 3e2ce808759b
Add branch test-yostqsxwqrlt to 361948b172e3
"###);
}

Expand Down Expand Up @@ -759,7 +768,7 @@ fn test_git_push_mixed() {
);
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Creating branch push-yqosqzytrlsw for revision @--
Creating branch push-yqosqzytrlsw for revision yqosqzytrlsw
Branch changes to push to origin:
Add branch push-yqosqzytrlsw to fa16a14170fb
Add branch branch-1 to 7decc7932d9c
Expand Down

0 comments on commit 871b4c5

Please sign in to comment.