forked from mirrors/jj
cli branch list
: list tracked branches
Add an option to list tracked branches only This option keeps most of the current `--all` printing logic, but: - Omits local Git-tracking branches 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>`
This commit is contained in:
parent
1cbf2b4acf
commit
e9243a7638
5 changed files with 177 additions and 8 deletions
|
@ -74,6 +74,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`
|
* 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 local Git-tracking branches by default.
|
||||||
|
|
||||||
### Fixed bugs
|
### Fixed bugs
|
||||||
|
|
||||||
* On Windows, symlinks in the repo are now materialized as regular files in the
|
* On Windows, symlinks in the repo are now materialized as regular files in the
|
||||||
|
|
|
@ -100,9 +100,14 @@ pub struct BranchDeleteArgs {
|
||||||
pub struct BranchListArgs {
|
pub struct BranchListArgs {
|
||||||
/// Show all tracking and non-tracking remote branches including the ones
|
/// Show all tracking and non-tracking remote branches including the ones
|
||||||
/// whose targets are synchronized with the local branches.
|
/// 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,
|
all: bool,
|
||||||
|
|
||||||
|
/// Show remote tracked branches only. Omits local Git-tracking branches by
|
||||||
|
/// default.
|
||||||
|
#[arg(long, short, conflicts_with_all = ["all"])]
|
||||||
|
tracked: bool,
|
||||||
|
|
||||||
/// Show branches whose local name matches
|
/// Show branches whose local name matches
|
||||||
///
|
///
|
||||||
/// By default, the specified name matches exactly. Use `glob:` prefix to
|
/// By default, the specified name matches exactly. Use `glob:` prefix to
|
||||||
|
@ -679,13 +684,19 @@ fn cmd_branch_list(
|
||||||
.map_or(true, |branch_names| branch_names.contains(name))
|
.map_or(true, |branch_names| branch_names.contains(name))
|
||||||
});
|
});
|
||||||
for (name, branch_target) in branches_to_list {
|
for (name, branch_target) in branches_to_list {
|
||||||
let (tracking_remote_refs, untracked_remote_refs) =
|
let (mut tracking_remote_refs, untracked_remote_refs) = branch_target
|
||||||
branch_target
|
.remote_refs
|
||||||
.remote_refs
|
.into_iter()
|
||||||
.into_iter()
|
.partition::<Vec<_>, _>(|&(_, remote_ref)| remote_ref.is_tracking());
|
||||||
.partition::<Vec<_>, _>(|&(_, remote_ref)| remote_ref.is_tracking());
|
|
||||||
|
|
||||||
if branch_target.local_target.is_present() || !tracking_remote_refs.is_empty() {
|
if args.tracked {
|
||||||
|
tracking_remote_refs
|
||||||
|
.retain(|&(remote, _)| remote != git::REMOTE_NAME_FOR_LOCAL_GIT_REPO);
|
||||||
|
}
|
||||||
|
|
||||||
|
if !args.tracked && branch_target.local_target.is_present()
|
||||||
|
|| !tracking_remote_refs.is_empty()
|
||||||
|
{
|
||||||
write!(formatter.labeled("branch"), "{name}")?;
|
write!(formatter.labeled("branch"), "{name}")?;
|
||||||
if branch_target.local_target.is_present() {
|
if branch_target.local_target.is_present() {
|
||||||
print_branch_target(formatter, branch_target.local_target)?;
|
print_branch_target(formatter, branch_target.local_target)?;
|
||||||
|
@ -696,7 +707,8 @@ fn cmd_branch_list(
|
||||||
|
|
||||||
for &(remote, remote_ref) in &tracking_remote_refs {
|
for &(remote, remote_ref) in &tracking_remote_refs {
|
||||||
let synced = remote_ref.target == *branch_target.local_target;
|
let synced = remote_ref.target == *branch_target.local_target;
|
||||||
if !args.all && synced {
|
|
||||||
|
if !args.all && !args.tracked && synced {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
write!(formatter, " ")?;
|
write!(formatter, " ")?;
|
||||||
|
|
|
@ -301,6 +301,10 @@ For information about branches, see https://github.com/martinvonz/jj/blob/main/d
|
||||||
|
|
||||||
Possible values: `true`, `false`
|
Possible values: `true`, `false`
|
||||||
|
|
||||||
|
* `-t`, `--tracked` — Show remote tracked branches only. Omits local Git-tracking branches by default
|
||||||
|
|
||||||
|
Possible values: `true`, `false`
|
||||||
|
|
||||||
* `-r`, `--revisions <REVISIONS>` — Show branches whose local targets are in the given revisions
|
* `-r`, `--revisions <REVISIONS>` — Show branches whose local targets are in the given revisions
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
fn get_log_output(test_env: &TestEnvironment, cwd: &Path) -> String {
|
||||||
let template = r#"branches ++ " " ++ commit_id.short()"#;
|
let template = r#"branches ++ " " ++ commit_id.short()"#;
|
||||||
test_env.jj_cmd_success(cwd, &["log", "-T", template])
|
test_env.jj_cmd_success(cwd, &["log", "-T", template])
|
||||||
|
|
|
@ -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).
|
$ # 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 local Git-tracking branches 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
|
### Automatic tracking of branches & `git.auto-local-branch` option
|
||||||
|
|
||||||
There are two situations where `jj` tracks branches automatically. `jj git
|
There are two situations where `jj` tracks branches automatically. `jj git
|
||||||
|
|
Loading…
Reference in a new issue