jj_cli/commands/git/
mod.rs1mod clone;
16mod colocation;
17mod export;
18mod fetch;
19mod import;
20mod init;
21mod push;
22mod remote;
23mod root;
24
25use std::io::Write as _;
26
27use clap::Subcommand;
28use clap::ValueEnum;
29use jj_lib::config::ConfigFile;
30use jj_lib::config::ConfigSource;
31use jj_lib::git;
32use jj_lib::git::UnexpectedGitBackendError;
33use jj_lib::ref_name::RemoteNameBuf;
34use jj_lib::ref_name::RemoteRefSymbol;
35use jj_lib::store::Store;
36
37use self::clone::GitCloneArgs;
38use self::clone::cmd_git_clone;
39use self::colocation::GitColocationCommand;
40use self::colocation::cmd_git_colocation;
41use self::export::GitExportArgs;
42use self::export::cmd_git_export;
43use self::fetch::GitFetchArgs;
44use self::fetch::cmd_git_fetch;
45use self::import::GitImportArgs;
46use self::import::cmd_git_import;
47use self::init::GitInitArgs;
48use self::init::cmd_git_init;
49use self::push::GitPushArgs;
50use self::push::cmd_git_push;
51pub use self::push::is_push_operation;
52use self::remote::RemoteCommand;
53use self::remote::cmd_git_remote;
54use self::root::GitRootArgs;
55use self::root::cmd_git_root;
56use crate::cli_util::CommandHelper;
57use crate::cli_util::WorkspaceCommandHelper;
58use crate::command_error::CommandError;
59use crate::command_error::user_error_with_message;
60use crate::config::ConfigEnv;
61use crate::ui::Ui;
62
63#[derive(Subcommand, Clone, Debug)]
73pub enum GitCommand {
74 Clone(GitCloneArgs),
75 #[command(subcommand)]
76 Colocation(GitColocationCommand),
77 Export(GitExportArgs),
78 Fetch(GitFetchArgs),
79 Import(GitImportArgs),
80 Init(GitInitArgs),
81 Push(GitPushArgs),
82 #[command(subcommand)]
83 Remote(RemoteCommand),
84 Root(GitRootArgs),
85}
86
87pub async fn cmd_git(
88 ui: &mut Ui,
89 command: &CommandHelper,
90 subcommand: &GitCommand,
91) -> Result<(), CommandError> {
92 match subcommand {
93 GitCommand::Clone(args) => cmd_git_clone(ui, command, args).await,
94 GitCommand::Colocation(subcommand) => cmd_git_colocation(ui, command, subcommand).await,
95 GitCommand::Export(args) => cmd_git_export(ui, command, args).await,
96 GitCommand::Fetch(args) => cmd_git_fetch(ui, command, args).await,
97 GitCommand::Import(args) => cmd_git_import(ui, command, args).await,
98 GitCommand::Init(args) => cmd_git_init(ui, command, args).await,
99 GitCommand::Push(args) => cmd_git_push(ui, command, args).await,
100 GitCommand::Remote(args) => cmd_git_remote(ui, command, args).await,
101 GitCommand::Root(args) => cmd_git_root(ui, command, args).await,
102 }
103}
104
105pub fn maybe_add_gitignore(workspace_command: &WorkspaceCommandHelper) -> Result<(), CommandError> {
106 if workspace_command.working_copy_shared_with_git() {
107 std::fs::write(
108 workspace_command
109 .workspace_root()
110 .join(".jj")
111 .join(".gitignore"),
112 "/*\n",
113 )
114 .map_err(|e| user_error_with_message("Failed to write .jj/.gitignore file", e))
115 } else {
116 Ok(())
117 }
118}
119
120fn get_single_remote(store: &Store) -> Result<Option<RemoteNameBuf>, UnexpectedGitBackendError> {
121 let mut names = git::get_all_remote_names(store)?;
122 Ok(match names.len() {
123 1 => names.pop(),
124 _ => None,
125 })
126}
127
128fn write_repository_level_trunk_alias(
130 ui: &Ui,
131 config_env: &ConfigEnv,
132 symbol: RemoteRefSymbol<'_>,
133) -> Result<(), CommandError> {
134 let Some(config_path) = config_env.repo_config_path(ui)? else {
135 return Ok(());
137 };
138 let mut file = ConfigFile::load_or_empty(ConfigSource::Repo, config_path)?;
139 file.set_value(["revset-aliases", "trunk()"], symbol.to_string())
140 .expect("initial repo config shouldn't have invalid values");
141 file.save()?;
142 writeln!(
143 ui.status(),
144 "Setting the revset alias `trunk()` to `{symbol}`",
145 )?;
146 Ok(())
147}
148
149#[derive(Copy, Clone, Debug, PartialEq, Eq, ValueEnum)]
150enum FetchTagsMode {
151 All,
153
154 Included,
157
158 None,
160}
161
162impl FetchTagsMode {
163 fn as_fetch_tags(&self) -> gix::remote::fetch::Tags {
164 match self {
165 Self::All => gix::remote::fetch::Tags::All,
166 Self::Included => gix::remote::fetch::Tags::Included,
167 Self::None => gix::remote::fetch::Tags::None,
168 }
169 }
170}