ok/jj
1
0
Fork 0
forked from mirrors/jj

templater: indicate if branch needs to be pushed to a remote

It's useful to know when you've modified a branch that exists on a
remote. A typical case is when you have pushed a branch to a remote
and then rewritten it. This commit adds an indication in the
`branches` template keyword. A branch that needs to be pushed to a
remote now has a `*` at the end (similar to how conflicted branches
have a `?` at the end). Note that the indication only considers
remotes where the branch currently exists, so there won't be an
indication that the branch has not been pushed to a remote.

Closes #254
This commit is contained in:
Martin von Zweigbergk 2022-11-04 09:39:46 -07:00 committed by Martin von Zweigbergk
parent 5e710bac66
commit 6c600e98cf
4 changed files with 94 additions and 2 deletions

View file

@ -38,6 +38,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* (#469) `jj git` subcommands will prompt for credentials when
required for HTTPS remotes rather than failing.
* (#254) Branches that have a different target on some remote than they do
locally are now indicated by an asterisk suffix (e.g. `main*`) in `jj log`.
### Fixed bugs
* `jj edit root` now fails gracefully.

View file

@ -22,11 +22,14 @@ branches from the remote will be imported as branches in your local repo.
Jujutsu also records the last seen position on each remote (just like Git's
remote-tracking branches). You can refer to these with
`<branch name>@<remote name>`, such as `jj co main@origin`. Most commands don't
`<branch name>@<remote name>`, such as `jj new main@origin`. Most commands don't
show the remote branch if it has the same target as the local branch. The local
branch (without `@<remote name>`) is considered the branch's desired target.
Consequently, if you want to update a branch on a remote, you first update the
branch locally and then push the update to the remote.
branch locally and then push the update to the remote. If a local branch also
exists on some remote but points to a different target there, `jj log` will
show the branch name with an asterisk suffix (e.g. `main*`). That is meant to
remind you that you may want to push the branch to some remote.
When you pull from a remote, any changes compared to the current record of the
remote's state will be propagated to the local branch. Let's say you run

View file

@ -240,6 +240,12 @@ impl TemplateProperty<Commit, String> for BranchProperty<'_> {
if local_target.has_add(context.id()) {
if local_target.is_conflict() {
names.push(format!("{}?", branch_name));
} else if branch_target
.remote_targets
.values()
.any(|remote_target| remote_target != local_target)
{
names.push(format!("{}*", branch_name));
} else {
names.push(branch_name.clone());
}

80
tests/test_templater.rs Normal file
View file

@ -0,0 +1,80 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::common::TestEnvironment;
pub mod common;
#[test]
fn test_templater_branches() {
let test_env = TestEnvironment::default();
test_env.jj_cmd_success(test_env.env_root(), &["init", "--git", "origin"]);
let origin_path = test_env.env_root().join("origin");
let origin_git_repo_path = origin_path
.join(".jj")
.join("repo")
.join("store")
.join("git");
// TODO: This initial export shouldn't be needed
test_env.jj_cmd_success(&origin_path, &["git", "export"]);
// Created some branches on the remote
test_env.jj_cmd_success(&origin_path, &["describe", "-m=description 1"]);
test_env.jj_cmd_success(&origin_path, &["branch", "create", "branch1"]);
test_env.jj_cmd_success(&origin_path, &["new", "root", "-m=description 2"]);
test_env.jj_cmd_success(&origin_path, &["branch", "create", "branch2"]);
test_env.jj_cmd_success(&origin_path, &["new", "root", "-m=description 3"]);
test_env.jj_cmd_success(&origin_path, &["branch", "create", "branch3"]);
test_env.jj_cmd_success(&origin_path, &["git", "export"]);
test_env.jj_cmd_success(
test_env.env_root(),
&[
"git",
"clone",
origin_git_repo_path.to_str().unwrap(),
"local",
],
);
let workspace_root = test_env.env_root().join("local");
// Rewrite branch1, move branch2 forward, create conflict in branch3, add
// new-branch
test_env.jj_cmd_success(
&workspace_root,
&["describe", "branch1", "-m", "modified branch1 commit"],
);
test_env.jj_cmd_success(&workspace_root, &["new", "branch2"]);
test_env.jj_cmd_success(&workspace_root, &["branch", "set", "branch2"]);
test_env.jj_cmd_success(&workspace_root, &["branch", "create", "new-branch"]);
test_env.jj_cmd_success(&workspace_root, &["describe", "branch3", "-m=local"]);
test_env.jj_cmd_success(&origin_path, &["describe", "branch3", "-m=origin"]);
test_env.jj_cmd_success(&origin_path, &["git", "export"]);
test_env.jj_cmd_success(&workspace_root, &["git", "fetch"]);
let output = test_env.jj_cmd_success(
&workspace_root,
&["log", "-T", r#"commit_id.short() " " branches"#],
);
insta::assert_snapshot!(output, @r###"
o 212985c08a44 branch3?
| @ cbf02da4e154 branch2* new-branch
| | o c794a4eab3b9 branch1*
| |/
|/|
| o 8cd8e5dc9595 branch2@origin
|/
o 000000000000
"###);
}