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

git init: add revset alias for trunk() when intializing with existing git repository

This commit is contained in:
Benjamin Tan 2024-05-31 18:56:05 +08:00
parent d8899e1ae7
commit 0c0e001262
5 changed files with 100 additions and 7 deletions

View file

@ -20,8 +20,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
individually instead of being passed a directory by setting individually instead of being passed a directory by setting
`merge-tools.$TOOL.diff-invocation-mode="file-by-file"` in config.toml. `merge-tools.$TOOL.diff-invocation-mode="file-by-file"` in config.toml.
* `jj git clone` adds the default branch of the remote as repository * `jj git clone` and `jj git init` with an existing git repository adds the
settings for `revset-aliases."trunk()"`.` default branch of the remote as repository settings for
`revset-aliases."trunk()"`.`
### Fixed bugs ### Fixed bugs

View file

@ -16,6 +16,7 @@ use std::io::Write;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::sync::Arc; use std::sync::Arc;
use jj_lib::git::{parse_git_ref, RefName};
use jj_lib::repo::{ReadonlyRepo, Repo}; use jj_lib::repo::{ReadonlyRepo, Repo};
use jj_lib::workspace::Workspace; use jj_lib::workspace::Workspace;
use jj_lib::{file_util, git}; use jj_lib::{file_util, git};
@ -23,8 +24,9 @@ use jj_lib::{file_util, git};
use crate::cli_util::{print_trackable_remote_branches, start_repo_transaction, CommandHelper}; use crate::cli_util::{print_trackable_remote_branches, start_repo_transaction, CommandHelper};
use crate::command_error::{user_error_with_hint, user_error_with_message, CommandError}; use crate::command_error::{user_error_with_hint, user_error_with_message, CommandError};
use crate::commands::git::maybe_add_gitignore; use crate::commands::git::maybe_add_gitignore;
use crate::config::{write_config_value_to_file, ConfigNamePathBuf};
use crate::git_util::{ use crate::git_util::{
is_colocated_git_workspace, print_failed_git_export, print_git_import_stats, get_git_repo, is_colocated_git_workspace, print_failed_git_export, print_git_import_stats,
}; };
use crate::ui::Ui; use crate::ui::Ui;
@ -152,6 +154,7 @@ pub fn do_init(
let mut workspace_command = command.for_loaded_repo(ui, workspace, repo)?; let mut workspace_command = command.for_loaded_repo(ui, workspace, repo)?;
maybe_add_gitignore(&workspace_command)?; maybe_add_gitignore(&workspace_command)?;
workspace_command.maybe_snapshot(ui)?; workspace_command.maybe_snapshot(ui)?;
maybe_set_repository_level_trunk_alias(ui, workspace_command.repo())?;
if !workspace_command.working_copy_shared_with_git() { if !workspace_command.working_copy_shared_with_git() {
let mut tx = workspace_command.start_transaction(); let mut tx = workspace_command.start_transaction();
jj_lib::git::import_head(tx.mut_repo())?; jj_lib::git::import_head(tx.mut_repo())?;
@ -210,3 +213,33 @@ fn init_git_refs(
)?; )?;
Ok(repo) Ok(repo)
} }
// Set repository level `trunk()` alias to the default branch for "origin".
pub fn maybe_set_repository_level_trunk_alias(
ui: &Ui,
repo: &Arc<ReadonlyRepo>,
) -> Result<(), CommandError> {
let git_repo = get_git_repo(repo.store())?;
if let Ok(reference) = git_repo.find_reference("refs/remotes/origin/HEAD") {
if let Some(reference_name) = reference.symbolic_target() {
if let Some(RefName::RemoteBranch {
branch: default_branch,
..
}) = parse_git_ref(reference_name)
{
let config_path = repo.repo_path().join("config.toml");
write_config_value_to_file(
&ConfigNamePathBuf::from_iter(["revset-aliases", "trunk()"]),
&format!("{default_branch}@origin"),
&config_path,
)?;
writeln!(
ui.status(),
"Setting the revset alias \"trunk()\" to \"{default_branch}@origin\"",
)?;
}
};
};
Ok(())
}

View file

@ -148,6 +148,65 @@ fn test_git_init_external(bare: bool) {
} }
} }
#[test_case(false; "full")]
#[test_case(true; "bare")]
fn test_git_init_external_import_trunk(bare: bool) {
let test_env = TestEnvironment::default();
let git_repo_path = test_env.env_root().join("git-repo");
let git_repo = init_git_repo(&git_repo_path, bare);
// Add remote branch "trunk" for remote "origin", and set it as "origin/HEAD"
let oid = git_repo
.find_reference("refs/heads/my-branch")
.unwrap()
.target()
.unwrap();
git_repo
.reference("refs/remotes/origin/trunk", oid, false, "")
.unwrap();
git_repo
.reference_symbolic(
"refs/remotes/origin/HEAD",
"refs/remotes/origin/trunk",
false,
"",
)
.unwrap();
let (stdout, stderr) = test_env.jj_cmd_ok(
test_env.env_root(),
&[
"git",
"init",
"repo",
"--git-repo",
git_repo_path.to_str().unwrap(),
],
);
insta::allow_duplicates! {
insta::assert_snapshot!(stdout, @"");
insta::assert_snapshot!(stderr, @r###"
Done importing changes from the underlying Git repo.
Setting the revset alias "trunk()" to "trunk@origin"
Working copy now at: sqpuoqvx f6950fc1 (empty) (no description set)
Parent commit : mwrttmos 8d698d4a my-branch trunk@origin | My commit message
Added 1 files, modified 0 files, removed 0 files
Initialized repo in "repo"
"###);
}
// "trunk()" alias should be set to remote "origin"'s default branch "trunk"
let stdout = test_env.jj_cmd_success(
&test_env.env_root().join("repo"),
&["config", "list", "--repo", "revset-aliases.\"trunk()\""],
);
insta::allow_duplicates! {
insta::assert_snapshot!(stdout, @r###"
revset-aliases."trunk()" = "trunk@origin"
"###);
}
}
#[test] #[test]
fn test_git_init_external_non_existent_directory() { fn test_git_init_external_non_existent_directory() {
let test_env = TestEnvironment::default(); let test_env = TestEnvironment::default();

View file

@ -362,9 +362,9 @@ for a comprehensive list.
tried. If more than one potential trunk commit exists, the newest one is tried. If more than one potential trunk commit exists, the newest one is
chosen. If none of the branches exist, the revset evaluates to `root()`. chosen. If none of the branches exist, the revset evaluates to `root()`.
When working with an existing Git repository (via `jj git clone`), When working with an existing Git repository (via `jj git clone` or
`trunk()` will be overridden at the repository level to the default branch of `jj git init`), `trunk()` will be overridden at the repository level
the remote. to the default branch of the remote `origin`.
You can [override](./config.md) this as appropriate. If you do, make sure it You can [override](./config.md) this as appropriate. If you do, make sure it
always resolves to exactly one commit. For example: always resolves to exactly one commit. For example:

View file

@ -62,7 +62,7 @@ impl fmt::Display for RefName {
} }
} }
fn parse_git_ref(ref_name: &str) -> Option<RefName> { pub fn parse_git_ref(ref_name: &str) -> Option<RefName> {
if let Some(branch_name) = ref_name.strip_prefix("refs/heads/") { if let Some(branch_name) = ref_name.strip_prefix("refs/heads/") {
// Git CLI says 'HEAD' is not a valid branch name // Git CLI says 'HEAD' is not a valid branch name
(branch_name != "HEAD").then(|| RefName::LocalBranch(branch_name.to_string())) (branch_name != "HEAD").then(|| RefName::LocalBranch(branch_name.to_string()))