forked from mirrors/jj
cmd: have jj branch list
report git-tracking (@git
) branches
This doesn't change the way @git branches are stored in `git_refs` as opposed to inside `BranchTarget` like normal remote-tracking branches. There are subtle differences in behavior with e.g. `jj branch forget` and I'm not sure how easy it is to rewrite `jj git import/export` to support a different way of storage. I've decided to call these "local-git tracking branches" since they track branches in the local git repository. "local git-tracking" branches sounds a bit more natural, but these could be confused with there are no remote git-tracking branches. If one had the idea these might exist, they would be confused with remote-tracking branches in the local git repo. This addresses a portion of #1666
This commit is contained in:
parent
9963879d15
commit
8df945b71d
6 changed files with 45 additions and 7 deletions
|
@ -101,6 +101,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
now shorter within the default log revset. You can override the default by
|
now shorter within the default log revset. You can override the default by
|
||||||
setting the `revsets.short-prefixes` config to a different revset.
|
setting the `revsets.short-prefixes` config to a different revset.
|
||||||
|
|
||||||
|
* The last seen state of branches in the underlying git repo is now presented by
|
||||||
|
`jj branch list` as a remote called `git` (e.g. `main@git`). Such branches
|
||||||
|
exist in colocated repos or if you use `jj git export`.
|
||||||
|
|
||||||
### Fixed bugs
|
### Fixed bugs
|
||||||
|
|
||||||
* Modify/delete conflicts now include context lines
|
* Modify/delete conflicts now include context lines
|
||||||
|
|
|
@ -27,7 +27,7 @@ use crate::op_store::RefTarget;
|
||||||
use crate::repo::{MutableRepo, Repo};
|
use crate::repo::{MutableRepo, Repo};
|
||||||
use crate::revset;
|
use crate::revset;
|
||||||
use crate::settings::GitSettings;
|
use crate::settings::GitSettings;
|
||||||
use crate::view::RefName;
|
use crate::view::{RefName, View};
|
||||||
|
|
||||||
#[derive(Error, Debug, PartialEq)]
|
#[derive(Error, Debug, PartialEq)]
|
||||||
pub enum GitImportError {
|
pub enum GitImportError {
|
||||||
|
@ -60,6 +60,16 @@ fn local_branch_name_to_ref_name(branch: &str) -> String {
|
||||||
format!("refs/heads/{branch}")
|
format!("refs/heads/{branch}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Eventually, git-tracking branches should no longer be stored in
|
||||||
|
// git_refs but with the other remote-tracking branches in BranchTarget. Note
|
||||||
|
// that there are important but subtle differences in behavior for, e.g. `jj
|
||||||
|
// branch forget`.
|
||||||
|
pub fn git_tracking_branches(view: &View) -> impl Iterator<Item = (&str, &RefTarget)> {
|
||||||
|
view.git_refs().iter().filter_map(|(ref_name, target)| {
|
||||||
|
ref_name_to_local_branch_name(ref_name).map(|branch_name| (branch_name, target))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) -> Result<(), git2::Error> {
|
fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) -> Result<(), git2::Error> {
|
||||||
// If multiple processes do git::import_refs() in parallel, this can fail to
|
// If multiple processes do git::import_refs() in parallel, this can fail to
|
||||||
// acquire a lock file even with force=true.
|
// acquire a lock file even with force=true.
|
||||||
|
|
|
@ -3,6 +3,7 @@ use std::collections::BTreeSet;
|
||||||
use clap::builder::NonEmptyStringValueParser;
|
use clap::builder::NonEmptyStringValueParser;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use jujutsu_lib::backend::{CommitId, ObjectId};
|
use jujutsu_lib::backend::{CommitId, ObjectId};
|
||||||
|
use jujutsu_lib::git::git_tracking_branches;
|
||||||
use jujutsu_lib::op_store::RefTarget;
|
use jujutsu_lib::op_store::RefTarget;
|
||||||
use jujutsu_lib::repo::Repo;
|
use jujutsu_lib::repo::Repo;
|
||||||
use jujutsu_lib::revset;
|
use jujutsu_lib::revset;
|
||||||
|
@ -258,6 +259,28 @@ fn cmd_branch_list(
|
||||||
let workspace_command = command.workspace_helper(ui)?;
|
let workspace_command = command.workspace_helper(ui)?;
|
||||||
let repo = workspace_command.repo();
|
let repo = workspace_command.repo();
|
||||||
|
|
||||||
|
let mut all_branches = repo.view().branches().clone();
|
||||||
|
for (branch_name, git_tracking_target) in git_tracking_branches(repo.view()) {
|
||||||
|
let branch_target = all_branches.entry(branch_name.to_owned()).or_default();
|
||||||
|
if branch_target.remote_targets.contains_key("git") {
|
||||||
|
// TODO(#1690): There should be a mechanism to prevent importing a
|
||||||
|
// remote named "git" in `jj git import`.
|
||||||
|
// TODO: This is not currently tested
|
||||||
|
writeln!(
|
||||||
|
ui.warning(),
|
||||||
|
"WARNING: Branch {branch_name} has a remote-tracking branch for a remote named \
|
||||||
|
`git`. Local-git tracking branches for it will not be shown.\nIt is recommended \
|
||||||
|
to rename that remote, as jj normally reserves the `@git` suffix to denote \
|
||||||
|
local-git tracking branches."
|
||||||
|
)?;
|
||||||
|
} else {
|
||||||
|
// TODO: `BTreeMap::try_insert` could be used here once that's stabilized.
|
||||||
|
branch_target
|
||||||
|
.remote_targets
|
||||||
|
.insert("git".to_string(), git_tracking_target.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let print_branch_target =
|
let print_branch_target =
|
||||||
|formatter: &mut dyn Formatter, target: Option<&RefTarget>| -> Result<(), CommandError> {
|
|formatter: &mut dyn Formatter, target: Option<&RefTarget>| -> Result<(), CommandError> {
|
||||||
match target {
|
match target {
|
||||||
|
@ -293,15 +316,12 @@ fn cmd_branch_list(
|
||||||
|
|
||||||
let mut formatter = ui.stdout_formatter();
|
let mut formatter = ui.stdout_formatter();
|
||||||
let formatter = formatter.as_mut();
|
let formatter = formatter.as_mut();
|
||||||
for (name, branch_target) in repo.view().branches() {
|
|
||||||
|
for (name, branch_target) in all_branches {
|
||||||
write!(formatter.labeled("branch"), "{name}")?;
|
write!(formatter.labeled("branch"), "{name}")?;
|
||||||
print_branch_target(formatter, branch_target.local_target.as_ref())?;
|
print_branch_target(formatter, branch_target.local_target.as_ref())?;
|
||||||
|
|
||||||
for (remote, remote_target) in branch_target
|
for (remote, remote_target) in branch_target.remote_targets.iter() {
|
||||||
.remote_targets
|
|
||||||
.iter()
|
|
||||||
.sorted_by_key(|(name, _target)| name.to_owned())
|
|
||||||
{
|
|
||||||
if Some(remote_target) == branch_target.local_target.as_ref() {
|
if Some(remote_target) == branch_target.local_target.as_ref() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -113,6 +113,8 @@ fn test_branch_forget_glob() {
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Test `jj branch list` with a remote named `git`
|
||||||
|
|
||||||
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])
|
||||||
|
|
|
@ -272,6 +272,7 @@ fn test_git_fetch_conflicting_branches_colocated() {
|
||||||
rem1 (conflicted):
|
rem1 (conflicted):
|
||||||
+ f652c32197cf (no description set)
|
+ f652c32197cf (no description set)
|
||||||
+ 6a21102783e8 message
|
+ 6a21102783e8 message
|
||||||
|
@git (behind by 1 commits): f652c32197cf (no description set)
|
||||||
@rem1 (behind by 1 commits): 6a21102783e8 message
|
@rem1 (behind by 1 commits): 6a21102783e8 message
|
||||||
"###);
|
"###);
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,7 @@ fn test_git_import_move_export_undo() {
|
||||||
test_env.jj_cmd_success(&repo_path, &["branch", "set", "a"]);
|
test_env.jj_cmd_success(&repo_path, &["branch", "set", "a"]);
|
||||||
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###"
|
||||||
a: 096dc80da670 (no description set)
|
a: 096dc80da670 (no description set)
|
||||||
|
@git (behind by 1 commits): 230dd059e1b0 (no description set)
|
||||||
"###);
|
"###);
|
||||||
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["git", "export"]), @"");
|
insta::assert_snapshot!(test_env.jj_cmd_success(&repo_path, &["git", "export"]), @"");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue