From a483252cf23d4f364658b6ce6e02f9f7bcd61cda Mon Sep 17 00:00:00 2001 From: Ilya Grigoriev Date: Sat, 10 Jun 2023 22:54:10 -0700 Subject: [PATCH] revset: allow checking out git-tracking (`@git`) branches --- CHANGELOG.md | 5 ++-- lib/src/git.rs | 4 +++ lib/src/revset.rs | 7 +++++ tests/test_git_import_export.rs | 47 +++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f95078f82..086ba09c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -102,8 +102,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 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`. + `jj branch list` as a remote called `git` (e.g. `main@git`). They can also be + referenced in revsets. Such branches exist in colocated repos or if you use + `jj git export`. ### Fixed bugs diff --git a/lib/src/git.rs b/lib/src/git.rs index 6fb0b182b..a10c0a51e 100644 --- a/lib/src/git.rs +++ b/lib/src/git.rs @@ -70,6 +70,10 @@ pub fn git_tracking_branches(view: &View) -> impl Iterator(view: &'a View, branch: &str) -> Option<&'a RefTarget> { + view.git_refs().get(&local_branch_name_to_ref_name(branch)) +} + 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 // acquire a lock file even with force=true. diff --git a/lib/src/revset.rs b/lib/src/revset.rs index 2b80a5139..7dc407998 100644 --- a/lib/src/revset.rs +++ b/lib/src/revset.rs @@ -31,6 +31,7 @@ use thiserror::Error; use crate::backend::{BackendError, BackendResult, ChangeId, CommitId, ObjectId}; use crate::commit::Commit; +use crate::git::get_git_tracking_branch; use crate::hex_util::to_forward_hex; use crate::index::{HexPrefix, PrefixResolution}; use crate::op_store::WorkspaceId; @@ -1640,6 +1641,12 @@ fn resolve_branch(repo: &dyn Repo, symbol: &str) -> Option> { return Some(target.adds()); } } + // A remote with name "git" will shadow local-git tracking branches + if remote_name == "git" { + if let Some(target) = get_git_tracking_branch(repo.view(), name) { + return Some(target.adds()); + } + } } None } diff --git a/tests/test_git_import_export.rs b/tests/test_git_import_export.rs index e10c91d49..d5ff1963f 100644 --- a/tests/test_git_import_export.rs +++ b/tests/test_git_import_export.rs @@ -20,6 +20,53 @@ use crate::common::{get_stderr_string, TestEnvironment}; pub mod common; +#[test] +fn test_resolution_of_git_tracking_branches() { + let test_env = TestEnvironment::default(); + test_env.jj_cmd_success(test_env.env_root(), &["init", "repo", "--git"]); + let repo_path = test_env.env_root().join("repo"); + test_env.jj_cmd_success(&repo_path, &["branch", "create", "main"]); + test_env.jj_cmd_success(&repo_path, &["describe", "-r", "main", "-m", "old_message"]); + + // Create local-git tracking branch + let stdout = test_env.jj_cmd_success(&repo_path, &["git", "export"]); + insta::assert_snapshot!(stdout, @""); + // Move the local branch somewhere else + test_env.jj_cmd_success(&repo_path, &["describe", "-r", "main", "-m", "new_message"]); + insta::assert_snapshot!(get_branch_output(&test_env, &repo_path), @r###" + main: 3af370264cdc new_message + @git (ahead by 1 commits, behind by 1 commits): 16d541ca40f4 old_message + "###); + + // Test that we can address both revisions + let stdout = test_env.jj_cmd_success( + &repo_path, + &[ + "log", + "-r=main", + "-T", + r#"commit_id ++ " " ++ description"#, + "--no-graph", + ], + ); + insta::assert_snapshot!(stdout, @r###" + 3af370264cdcbba791762f8ef6bc79b456dcbf3b new_message + "###); + let stdout = test_env.jj_cmd_success( + &repo_path, + &[ + "log", + "-r=main@git", + "-T", + r#"commit_id ++ " " ++ description"#, + "--no-graph", + ], + ); + insta::assert_snapshot!(stdout, @r###" + 16d541ca40f42baf2dea41aa61a0b5f1cbf1f91b old_message + "###); +} + #[test] fn test_git_export_conflicting_git_refs() { let test_env = TestEnvironment::default();