Skip to content

Commit

Permalink
cli git push: new --tracked option
Browse files Browse the repository at this point in the history
  • Loading branch information
ilyagr committed Feb 6, 2024
1 parent cdbbde1 commit d16a3fc
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `jj branch rename` will now warn if the renamed branch has a remote branch, since
those will have to be manually renamed outside of `jj`.

* `jj git push` gained a `--tracked` option, to push all the tracked branches.

* There's now a virtual root operation, similar to the [virtual root
commit](docs/glossary.md#root-commit). It appears at the end of `jj op log`.

Expand Down
24 changes: 23 additions & 1 deletion cli/src/commands/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ pub struct GitCloneArgs {
/// branch names based on the change IDs of specific commits.
#[derive(clap::Args, Clone, Debug)]
#[command(group(ArgGroup::new("specific").args(&["branch", "change", "revisions"]).multiple(true)))]
#[command(group(ArgGroup::new("what").args(&["all", "deleted"]).conflicts_with("specific")))]
#[command(group(ArgGroup::new("what").args(&["all", "deleted", "tracked"]).conflicts_with("specific")))]
pub struct GitPushArgs {
/// The remote to push to (only named remotes are supported)
#[arg(long)]
Expand All @@ -205,6 +205,16 @@ pub struct GitPushArgs {
/// https://martinvonz.github.io/jj/latest/revsets#string-patterns.
#[arg(long, short, value_parser = parse_string_pattern)]
branch: Vec<StringPattern>,
/// Push all tracked branches (including deleted branches)
///
/// This usually means that the branch was already pushed to or fetched from
/// the relevant remote. For details, see
/// https://martinvonz.github.io/jj/latest/branches#remotes-and-tracked-branches
///
/// Not yet implemented, TODO(#2946): `jj git push --tracked --deleted`
/// would make sense, but is not currently allowed.
#[arg(long)]
tracked: bool,
/// Push all branches (including deleted branches)
#[arg(long)]
all: bool,
Expand Down Expand Up @@ -741,6 +751,18 @@ fn cmd_git_push(
}
}
tx_description = format!("push all branches to git remote {remote}");
} else if args.tracked {
for (branch_name, targets) in repo.view().local_remote_branches(&remote) {
if !targets.remote_ref.is_tracking() {
continue;
}
match classify_branch_update(branch_name, &remote, targets) {
Ok(Some(update)) => branch_updates.push((branch_name.to_owned(), update)),
Ok(None) => {}
Err(reason) => reason.print(ui)?,
}
}
tx_description = format!("push all tracked branches to git remote {remote}");
} else if args.deleted {
for (branch_name, targets) in repo.view().local_remote_branches(&remote) {
if targets.local_target.is_present() {
Expand Down
4 changes: 4 additions & 0 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -894,6 +894,10 @@ By default, pushes any branches pointing to `remote_branches(remote=<remote>)..@
* `--remote <REMOTE>` — The remote to push to (only named remotes are supported)
* `-b`, `--branch <BRANCH>` — Push only this branch (can be repeated)
* `--tracked` — Push all tracked branches (including deleted branches)
Possible values: `true`, `false`
* `--all` — Push all branches (including deleted branches)
Possible values: `true`, `false`
Expand Down
70 changes: 70 additions & 0 deletions cli/tests/test_git_push.rs
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,76 @@ fn test_git_push_deleted_untracked() {
"###);
}

#[test]
fn test_git_push_tracked_vs_all() {
let (test_env, workspace_root) = set_up();
test_env.jj_cmd_ok(&workspace_root, &["new", "branch1", "-mmoved branch1"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "set", "branch1"]);
test_env.jj_cmd_ok(&workspace_root, &["new", "branch2", "-mmoved branch2"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "delete", "branch2"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "untrack", "branch1@origin"]);
test_env.jj_cmd_ok(&workspace_root, &["branch", "create", "branch3"]);
let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);
insta::assert_snapshot!(stdout, @r###"
branch1: vruxwmqv a25f24af (empty) moved branch1
branch1@origin: lzmmnrxq 45a3aa29 (empty) description 1
branch2 (deleted)
@origin: rlzusymt 8476341e (empty) description 2
(this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)
branch3: znkkpsqq 998d6a78 (empty) moved branch2
"###);

// At this point, only branch2 is still tracked. `jj git push --tracked` would
// try to push it and no other branches.
let (_stdout, stderr) =
test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--tracked", "--dry-run"]);
insta::assert_snapshot!(stderr, @r###"
Branch changes to push to origin:
Delete branch branch2 from 8476341eb395
Dry-run requested, not pushing.
"###);

// Untrack the last remaining tracked branch.
test_env.jj_cmd_ok(&workspace_root, &["branch", "untrack", "branch2@origin"]);
let stdout = test_env.jj_cmd_success(&workspace_root, &["branch", "list", "--all"]);
insta::assert_snapshot!(stdout, @r###"
branch1: vruxwmqv a25f24af (empty) moved branch1
branch1@origin: lzmmnrxq 45a3aa29 (empty) description 1
branch2@origin: rlzusymt 8476341e (empty) description 2
branch3: znkkpsqq 998d6a78 (empty) moved branch2
"###);

// Now, no branches are tracked. --tracked does not push anything
let (_stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--tracked"]);
insta::assert_snapshot!(stderr, @r###"
Nothing changed.
"###);

// All branches are still untracked.
// - --all tries to push branch1, but fails because a branch with the same
// name exist on the remote.
// - --all succeeds in pushing branch3, since there is no branch of the same
// name on the remote.
// - It does not try to push branch2.
//
// TODO: Not trying to push branch2 could be considered correct, or perhaps
// we want to consider this as a deletion of the branch that failed because
// the branch was untracked. In the latter case, an error message should be
// printed. Some considerations:
// - Whatever we do should be consistent with what `jj branch list` does; it
// currently does *not* list branches like branch2 as "about to be deleted",
// as can be seen above.
// - We could consider showing some hint on `jj branch untrack branch2@origin`
// instead of showing an error here.
let (_stdout, stderr) = test_env.jj_cmd_ok(&workspace_root, &["git", "push", "--all"]);
insta::assert_snapshot!(stderr, @r###"
Non-tracking remote branch branch1@origin exists
Hint: Run `jj branch track branch1@origin` to import the remote branch.
Branch changes to push to origin:
Add branch branch3 to 998d6a7853d9
"###);
}

#[test]
fn test_git_push_moved_forward_untracked() {
let (test_env, workspace_root) = set_up();
Expand Down

0 comments on commit d16a3fc

Please sign in to comment.