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

cli: Move git_init() from init.rs to git.rs

* Move git_init() to cli/src/commands/git.rs and call it from there.
* Move print_trackable_remote_branches into cli_util since it's not git specific,
  but would apply to any backend that supports remote branches.
* A no-op change. A follow up PR will make use of this.
This commit is contained in:
Essien Ita Essien 2024-01-15 22:31:33 +00:00 committed by Essien Ita Essien
parent 31e4061bab
commit bcdb9beb6c
3 changed files with 89 additions and 92 deletions

View file

@ -61,6 +61,7 @@ use jj_lib::signing::SignInitError;
use jj_lib::str_util::{StringPattern, StringPatternParseError};
use jj_lib::transaction::Transaction;
use jj_lib::tree::TreeMergeError;
use jj_lib::view::View;
use jj_lib::working_copy::{
CheckoutStats, LockedWorkingCopy, ResetError, SnapshotError, SnapshotOptions, WorkingCopy,
WorkingCopyFactory, WorkingCopyStateError,
@ -2069,6 +2070,40 @@ Discard the conflicting changes with `jj restore --from {}`.",
Ok(())
}
pub fn print_trackable_remote_branches(ui: &Ui, view: &View) -> io::Result<()> {
let remote_branch_names = view
.branches()
.filter(|(_, branch_target)| branch_target.local_target.is_present())
.flat_map(|(name, branch_target)| {
branch_target
.remote_refs
.into_iter()
.filter(|&(_, remote_ref)| !remote_ref.is_tracking())
.map(move |(remote, _)| format!("{name}@{remote}"))
})
.collect_vec();
if remote_branch_names.is_empty() {
return Ok(());
}
writeln!(
ui.hint(),
"The following remote branches aren't associated with the existing local branches:"
)?;
let mut formatter = ui.stderr_formatter();
for full_name in &remote_branch_names {
write!(formatter, " ")?;
writeln!(formatter.labeled("branch"), "{full_name}")?;
}
drop(formatter);
writeln!(
ui.hint(),
"Hint: Run `jj branch track {names}` to keep local branches updated on future pulls.",
names = remote_branch_names.join(" "),
)?;
Ok(())
}
pub fn parse_string_pattern(src: &str) -> Result<StringPattern, StringPatternParseError> {
if let Some((kind, pat)) = src.split_once(':') {
StringPattern::from_str_kind(pat, kind)

View file

@ -21,6 +21,7 @@ use std::{fmt, fs, io};
use clap::{ArgGroup, Subcommand};
use itertools::Itertools;
use jj_lib::backend::TreeValue;
use jj_lib::file_util;
use jj_lib::git::{
self, parse_gitmodules, GitBranchPushTargets, GitFetchError, GitFetchStats, GitPushError,
};
@ -39,9 +40,10 @@ use jj_lib::workspace::Workspace;
use maplit::hashset;
use crate::cli_util::{
parse_string_pattern, resolve_multiple_nonempty_revsets, short_change_hash, short_commit_hash,
user_error, user_error_with_hint, user_error_with_hint_opt, user_error_with_message,
CommandError, CommandHelper, RevisionArg, WorkspaceCommandHelper,
parse_string_pattern, print_trackable_remote_branches, resolve_multiple_nonempty_revsets,
short_change_hash, short_commit_hash, user_error, user_error_with_hint,
user_error_with_hint_opt, user_error_with_message, CommandError, CommandHelper, RevisionArg,
WorkspaceCommandHelper,
};
use crate::git_util::{
get_git_repo, print_failed_git_export, print_git_import_stats, with_remote_git_callbacks,
@ -311,6 +313,54 @@ fn cmd_git_remote_list(
Ok(())
}
pub fn git_init(
ui: &mut Ui,
command: &CommandHelper,
workspace_root: &Path,
git_repo: Option<&str>,
) -> Result<(), CommandError> {
let cwd = command.cwd().canonicalize().unwrap();
let relative_wc_path = file_util::relative_path(&cwd, workspace_root);
if let Some(git_store_str) = git_repo {
let git_store_path = cwd.join(git_store_str);
let (workspace, repo) =
Workspace::init_external_git(command.settings(), workspace_root, &git_store_path)?;
let mut workspace_command = command.for_loaded_repo(ui, workspace, repo)?;
maybe_add_gitignore(&workspace_command)?;
// Import refs first so all the reachable commits are indexed in
// chronological order.
workspace_command.import_git_refs(ui)?;
workspace_command.maybe_snapshot(ui)?;
if !workspace_command.working_copy_shared_with_git() {
let mut tx = workspace_command.start_transaction();
jj_lib::git::import_head(tx.mut_repo())?;
if let Some(git_head_id) = tx.mut_repo().view().git_head().as_normal().cloned() {
let git_head_commit = tx.mut_repo().store().get_commit(&git_head_id)?;
tx.check_out(&git_head_commit)?;
}
if tx.mut_repo().has_changes() {
tx.finish(ui, "import git head")?;
}
}
print_trackable_remote_branches(ui, workspace_command.repo().view())?;
} else {
if workspace_root.join(".git").exists() {
return Err(user_error_with_hint(
"Did not create a jj repo because there is an existing Git repo in this directory.",
format!(
r#"To create a repo backed by the existing Git repo, run `jj init --git-repo={}` instead."#,
relative_wc_path.display()
),
));
}
Workspace::init_internal_git(command.settings(), workspace_root)?;
}
Ok(())
}
#[tracing::instrument(skip(ui, command))]
fn cmd_git_fetch(
ui: &mut Ui,

View file

@ -12,15 +12,10 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::io;
use std::io::Write;
use std::path::Path;
use clap::ArgGroup;
use itertools::Itertools as _;
use jj_lib::file_util;
use jj_lib::repo::Repo;
use jj_lib::view::View;
use jj_lib::workspace::Workspace;
use tracing::instrument;
@ -59,7 +54,7 @@ pub(crate) fn cmd_init(
.map_err(|e| user_error_with_message("Failed to create workspace", e))?;
if args.git || args.git_repo.is_some() {
git_init(ui, command, &wc_path, args.git_repo.as_deref())?;
git::git_init(ui, command, &wc_path, args.git_repo.as_deref())?;
} else {
if !command.settings().allow_native_backend() {
return Err(user_error_with_hint(
@ -79,86 +74,3 @@ Set `ui.allow-init-native` to allow initializing a repo with the native backend.
)?;
Ok(())
}
fn print_trackable_remote_branches(ui: &Ui, view: &View) -> io::Result<()> {
let remote_branch_names = view
.branches()
.filter(|(_, branch_target)| branch_target.local_target.is_present())
.flat_map(|(name, branch_target)| {
branch_target
.remote_refs
.into_iter()
.filter(|&(_, remote_ref)| !remote_ref.is_tracking())
.map(move |(remote, _)| format!("{name}@{remote}"))
})
.collect_vec();
if remote_branch_names.is_empty() {
return Ok(());
}
writeln!(
ui.hint(),
"The following remote branches aren't associated with the existing local branches:"
)?;
let mut formatter = ui.stderr_formatter();
for full_name in &remote_branch_names {
write!(formatter, " ")?;
writeln!(formatter.labeled("branch"), "{full_name}")?;
}
drop(formatter);
writeln!(
ui.hint(),
"Hint: Run `jj branch track {names}` to keep local branches updated on future pulls.",
names = remote_branch_names.join(" "),
)?;
Ok(())
}
// TODO(essiene): Move to cli/src/commands/git.rs for `jj git init`
fn git_init(
ui: &mut Ui,
command: &CommandHelper,
workspace_root: &Path,
git_repo: Option<&str>,
) -> Result<(), CommandError> {
let cwd = command.cwd().canonicalize().unwrap();
let relative_wc_path = file_util::relative_path(&cwd, workspace_root);
if let Some(git_store_str) = git_repo {
let git_store_path = cwd.join(git_store_str);
let (workspace, repo) =
Workspace::init_external_git(command.settings(), workspace_root, &git_store_path)?;
let mut workspace_command = command.for_loaded_repo(ui, workspace, repo)?;
git::maybe_add_gitignore(&workspace_command)?;
// Import refs first so all the reachable commits are indexed in
// chronological order.
workspace_command.import_git_refs(ui)?;
workspace_command.maybe_snapshot(ui)?;
if !workspace_command.working_copy_shared_with_git() {
let mut tx = workspace_command.start_transaction();
jj_lib::git::import_head(tx.mut_repo())?;
if let Some(git_head_id) = tx.mut_repo().view().git_head().as_normal().cloned() {
let git_head_commit = tx.mut_repo().store().get_commit(&git_head_id)?;
tx.check_out(&git_head_commit)?;
}
if tx.mut_repo().has_changes() {
tx.finish(ui, "import git head")?;
}
}
print_trackable_remote_branches(ui, workspace_command.repo().view())?;
} else {
if workspace_root.join(".git").exists() {
return Err(user_error_with_hint(
"Did not create a jj repo because there is an existing Git repo in this directory.",
format!(
r#"To create a repo backed by the existing Git repo, run `jj init --git-repo={}` instead."#,
relative_wc_path.display()
),
));
}
Workspace::init_internal_git(command.settings(), workspace_root)?;
}
Ok(())
}