105 lines · 3.6 KB · Rust
RawDownload
// Copyright 2020-2023 The Jujutsu Authors//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at//// https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License. use itertools::Itertools;use jj_lib::repo::Repo;use jj_lib::settings::ConfigResultExt as _;use jj_lib::settings::UserSettings;use jj_lib::str_util::StringPattern; use crate::cli_util::CommandHelper;use crate::command_error::CommandError;use crate::commands::git::get_single_remote;use crate::git_util::get_git_repo;use crate::git_util::git_fetch;use crate::ui::Ui; /// Fetch from a Git remote////// If a working-copy commit gets abandoned, it will be given a new, empty/// commit. This is true in general; it is not specific to this command.#[derive(clap::Args, Clone, Debug)]pub struct GitFetchArgs {    /// Fetch only some of the branches    ///    /// By default, the specified name matches exactly. Use `glob:` prefix to    /// expand `*` as a glob. The other wildcard characters aren't supported.    #[arg(long, short, alias="bookmark", default_value = "glob:*", value_parser = StringPattern::parse)]    branch: Vec<StringPattern>,    /// The remote to fetch from (only named remotes are supported, can be    /// repeated)    #[arg(long = "remote", value_name = "REMOTE")]    remotes: Vec<String>,    /// Fetch from all remotes    #[arg(long, conflicts_with = "remotes")]    all_remotes: bool,} #[tracing::instrument(skip(ui, command))]pub fn cmd_git_fetch(    ui: &mut Ui,    command: &CommandHelper,    args: &GitFetchArgs,) -> Result<(), CommandError> {    let mut workspace_command = command.workspace_helper(ui)?;    let git_repo = get_git_repo(workspace_command.repo().store())?;    let remotes = if args.all_remotes {        get_all_remotes(&git_repo)?    } else if args.remotes.is_empty() {        get_default_fetch_remotes(ui, command.settings(), &git_repo)?    } else {        args.remotes.clone()    };    let mut tx = workspace_command.start_transaction();    git_fetch(ui, &mut tx, &git_repo, &remotes, &args.branch)?;    tx.finish(        ui,        format!("fetch from git remote(s) {}", remotes.iter().join(",")),    )?;    Ok(())} const DEFAULT_REMOTE: &str = "origin"; fn get_default_fetch_remotes(    ui: &Ui,    settings: &UserSettings,    git_repo: &git2::Repository,) -> Result<Vec<String>, CommandError> {    const KEY: &str = "git.fetch";    if let Ok(remotes) = settings.config().get(KEY) {        Ok(remotes)    } else if let Some(remote) = settings.config().get_string(KEY).optional()? {        Ok(vec![remote])    } else if let Some(remote) = get_single_remote(git_repo)? {        // if nothing was explicitly configured, try to guess        if remote != DEFAULT_REMOTE {            writeln!(                ui.hint_default(),                "Fetching from the only existing remote: {remote}"            )?;        }        Ok(vec![remote])    } else {        Ok(vec![DEFAULT_REMOTE.to_owned()])    }} fn get_all_remotes(git_repo: &git2::Repository) -> Result<Vec<String>, CommandError> {    let git_remotes = git_repo.remotes()?;    Ok(git_remotes        .iter()        .filter_map(|x| x.map(ToOwned::to_owned))        .collect())}