Skip to content

Commit

Permalink
cli branch list: list tracked branches
Browse files Browse the repository at this point in the history
Add an option to list tracked branches only

This option keeps most of the current `--all` printing logic, but:

- Omits the git remote by default (can be extended to support
  filtering by remote).
- Skip over the branch altogether if it doesn't contain tracked remotes
- Don't print the untracked_remote_refs at the end

Usage:

`jj branch list -t`
`jj branch list --tracked`
`jj branch list --tracked <branch name>`
  • Loading branch information
prscoelho committed Feb 23, 2024
1 parent f97e929 commit 6dab2fc
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 10 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

* Added completions for [Nushell](https://nushell.sh) to `jj util completion`

* `jj branch list` now supports a `--tracked/-t` option which can be used to
show tracked branches only. Omits the git remote by default.

### Fixed bugs

* On Windows, symlinks in the repo are now materialized as regular files in the
Expand Down
27 changes: 19 additions & 8 deletions cli/src/commands/branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,13 @@ pub struct BranchDeleteArgs {
pub struct BranchListArgs {
/// Show all tracking and non-tracking remote branches including the ones
/// whose targets are synchronized with the local branches.
#[arg(long, short, conflicts_with_all = ["names", "revisions"])]
#[arg(long, short, conflicts_with_all = ["names", "revisions", "tracked"])]
all: bool,

/// Show remote tracked branches only. Omits the git remote by default.
#[arg(long, short, conflicts_with_all = ["all"])]
tracked: bool,

/// Show branches whose local name matches
///
/// By default, the specified name matches exactly. Use `glob:` prefix to
Expand Down Expand Up @@ -679,13 +683,19 @@ fn cmd_branch_list(
.map_or(true, |branch_names| branch_names.contains(name))
});
for (name, branch_target) in branches_to_list {
let (tracking_remote_refs, untracked_remote_refs) =
branch_target
.remote_refs
.into_iter()
.partition::<Vec<_>, _>(|&(_, remote_ref)| remote_ref.is_tracking());
let (mut tracking_remote_refs, untracked_remote_refs) = branch_target
.remote_refs
.into_iter()
.partition::<Vec<_>, _>(|&(_, remote_ref)| remote_ref.is_tracking());

if args.tracked {
tracking_remote_refs
.retain(|&(remote, _)| remote != git::REMOTE_NAME_FOR_LOCAL_GIT_REPO);
}

if branch_target.local_target.is_present() || !tracking_remote_refs.is_empty() {
if !args.tracked && branch_target.local_target.is_present()
|| !tracking_remote_refs.is_empty()
{
write!(formatter.labeled("branch"), "{name}")?;
if branch_target.local_target.is_present() {
print_branch_target(formatter, branch_target.local_target)?;
Expand All @@ -696,7 +706,8 @@ fn cmd_branch_list(

for &(remote, remote_ref) in &tracking_remote_refs {
let synced = remote_ref.target == *branch_target.local_target;
if !args.all && synced {

if !args.all && !args.tracked && synced {
continue;
}
write!(formatter, " ")?;
Expand Down
6 changes: 4 additions & 2 deletions cli/tests/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
source: cli/tests/test_generate_md_cli_help.rs
description: "AUTO-GENERATED FILE, DO NOT EDIT. This cli reference is generated as an `insta` snapshot. MkDocs follows they symlink from docs/cli-reference.md to the snap. Unfortunately, `insta` unavoidably creates this header. Luckily, MkDocs ignores the header since it has the same format as Markdown headers. TODO: MkDocs may fail on Windows if symlinks are not enabled in the OS settings"
---

<!-- BEGIN MARKDOWN-->

# Command-Line Help for `jj`
Expand Down Expand Up @@ -302,6 +301,10 @@ For information about branches, see https://github.com/martinvonz/jj/blob/main/d
Possible values: `true`, `false`
* `-t`, `--tracked` — Show remote tracked branches only. Omits the git remote by default
Possible values: `true`, `false`
* `-r`, `--revisions <REVISIONS>` — Show branches whose local targets are in the given revisions
Expand Down Expand Up @@ -1972,4 +1975,3 @@ For information about stale working copies, see https://github.com/martinvonz/jj
This document was generated automatically by
<a href="https://crates.io/crates/clap-markdown"><code>clap-markdown</code></a>.
</i></small>
142 changes: 142 additions & 0 deletions cli/tests/test_branch_command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1206,6 +1206,148 @@ fn test_branch_list_much_remote_divergence() {
"###);
}

#[test]
fn test_branch_list_tracked() {
let test_env = TestEnvironment::default();
test_env.add_config("git.auto-local-branch = true");

// Initialize remote refs
test_env.jj_cmd_ok(test_env.env_root(), &["init", "remote", "--git"]);
let remote_path = test_env.env_root().join("remote");
for branch in [
"remote-sync",
"remote-unsync",
"remote-untrack",
"remote-delete",
] {
test_env.jj_cmd_ok(&remote_path, &["new", "root()", "-m", branch]);
test_env.jj_cmd_ok(&remote_path, &["branch", "create", branch]);
}
test_env.jj_cmd_ok(&remote_path, &["new"]);
test_env.jj_cmd_ok(&remote_path, &["git", "export"]);

// Initialize local refs
let mut remote_git_path = test_env.env_root().join("remote");
remote_git_path.extend([".jj", "repo", "store", "git"]);
test_env.jj_cmd_ok(
test_env.env_root(),
&[
"git",
"clone",
"--colocate",
remote_git_path.to_str().unwrap(),
"local",
],
);

test_env.jj_cmd_ok(test_env.env_root(), &["init", "upstream", "--git"]);

// Initialize a second remote
let mut upstream_git_path = test_env.env_root().join("upstream");
test_env.jj_cmd_ok(
&upstream_git_path,
&["new", "root()", "-m", "upstream-sync"],
);
test_env.jj_cmd_ok(&upstream_git_path, &["branch", "create", "upstream-sync"]);
test_env.jj_cmd_ok(&upstream_git_path, &["new"]);
test_env.jj_cmd_ok(&upstream_git_path, &["git", "export"]);

upstream_git_path.extend([".jj", "repo", "store", "git"]);

let local_path = test_env.env_root().join("local");

test_env.jj_cmd_ok(
&local_path,
&[
"git",
"remote",
"add",
"upstream",
upstream_git_path.to_str().unwrap(),
],
);
test_env.jj_cmd_ok(&local_path, &["git", "fetch", "--all-remotes"]);

test_env.jj_cmd_ok(&local_path, &["new", "root()", "-m", "local-only"]);
test_env.jj_cmd_ok(&local_path, &["branch", "create", "local-only"]);

// Mutate refs in local repository
test_env.jj_cmd_ok(&local_path, &["branch", "delete", "remote-delete"]);
test_env.jj_cmd_ok(&local_path, &["branch", "delete", "remote-untrack"]);
test_env.jj_cmd_ok(&local_path, &["branch", "untrack", "remote-untrack@origin"]);
test_env.jj_cmd_ok(
&local_path,
&[
"git",
"push",
"--remote",
"upstream",
"--branch",
"remote-unsync",
],
);
test_env.jj_cmd_ok(
&local_path,
&["branch", "set", "--allow-backwards", "remote-unsync"],
);

insta::assert_snapshot!(
test_env.jj_cmd_success(&local_path, &["branch", "list", "--all"]), @r###"
local-only: nmzmmopx e1da745b (empty) local-only
@git: nmzmmopx e1da745b (empty) local-only
remote-delete (deleted)
@origin: mnmymoky 203e60eb (empty) remote-delete
(this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)
remote-sync: zwtyzrop c761c7ea (empty) remote-sync
@git: zwtyzrop c761c7ea (empty) remote-sync
@origin: zwtyzrop c761c7ea (empty) remote-sync
remote-unsync: nmzmmopx e1da745b (empty) local-only
@git: nmzmmopx e1da745b (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
@upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
remote-untrack@origin: vmortlor 71a16b05 (empty) remote-untrack
upstream-sync: lolpmnqw 32fa6da0 (empty) upstream-sync
@git: lolpmnqw 32fa6da0 (empty) upstream-sync
@upstream: lolpmnqw 32fa6da0 (empty) upstream-sync
"###);

insta::assert_snapshot!(
test_env.jj_cmd_success(&local_path, &["branch", "list", "--tracked"]), @r###"
remote-delete (deleted)
@origin: mnmymoky 203e60eb (empty) remote-delete
(this branch will be *deleted permanently* on the remote on the next `jj git push`. Use `jj branch forget` to prevent this)
remote-sync: zwtyzrop c761c7ea (empty) remote-sync
@origin: zwtyzrop c761c7ea (empty) remote-sync
remote-unsync: nmzmmopx e1da745b (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
@upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
upstream-sync: lolpmnqw 32fa6da0 (empty) upstream-sync
@upstream: lolpmnqw 32fa6da0 (empty) upstream-sync
"###
);

insta::assert_snapshot!(
test_env.jj_cmd_success(&local_path, &["branch", "list", "--tracked", "remote-unsync"]), @r###"
remote-unsync: nmzmmopx e1da745b (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
@upstream (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
"###);

insta::assert_snapshot!(
test_env.jj_cmd_success(&local_path, &["branch", "list", "--tracked", "remote-untrack"]), @"");

test_env.jj_cmd_ok(
&local_path,
&["branch", "untrack", "remote-unsync@upstream"],
);

insta::assert_snapshot!(
test_env.jj_cmd_success(&local_path, &["branch", "list", "--tracked", "remote-unsync"]), @r###"
remote-unsync: nmzmmopx e1da745b (empty) local-only
@origin (ahead by 1 commits, behind by 1 commits): qpsqxpyq 38ef8af7 (empty) remote-unsync
"###);
}

fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String {
let template = r#"branches ++ " " ++ commit_id.short()"#;
test_env.jj_cmd_success(cwd, &["log", "-T", template])
Expand Down
8 changes: 8 additions & 0 deletions docs/branches.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ $ # The local branch (e.g. stuff) is unaffected. It may or may not still
$ # be tracking branches on other remotes (e.g. stuff@upstream).
```

### Listing tracked branches

To list tracked branches, you can `jj branch list --tracked` or `jj branch list -t`.
This command omits the git remote by default.

You can see if a specific branch is tracked with `jj branch list --tracked <branch name>`.


### Automatic tracking of branches & `git.auto-local-branch` option

There are two situations where `jj` tracks branches automatically. `jj git
Expand Down

0 comments on commit 6dab2fc

Please sign in to comment.