Как выполнить "git pull" с корзиной Rust git2? - PullRequest
1 голос
/ 08 ноября 2019

Ящик git2 не имеет прямого способа выполнить действие "git pull".

Я видел этот вопрос и пытался сделать то же самое (детская площадка ):

use std::fs;
use std::fs::File;
use std::io::{stderr, stdout, Write};
use std::path::Path;

use git2::{Commit, Error, Index, MergeOptions, ObjectType, Repository, ResetType};

struct Repo {
    url: &'static str,
    path: &'static str,
    branch: &'static str,
}

impl Repo {
    fn reset(&self, path: &Path) {
        let repo = match Repository::open(path) {
            Ok(repo) => repo,
            Err(e) => panic!("Failed to open: {}", e),
        };
        repo.reset(
            &repo.revparse_single("HEAD").unwrap(),
            ResetType::Hard,
            None,
        )
        .unwrap();
    }

    fn clone(&self) {
        let repo = match Repository::clone(self.url, self.path) {
            Ok(repo) => repo,
            Err(e) => panic!("failed to init: {}", e),
        };
    }

    fn find_last_commit<'repo>(&self, repo: &'repo Repository) -> Result<Commit<'repo>, Error> {
        let obj = repo.head()?.resolve()?.peel(ObjectType::Commit)?;
        match obj.into_commit() {
            Ok(c) => Ok(c),
            _ => Err(Error::from_str("commit error")),
        }
    }

    fn pull(&self, path: &Path) -> Result<Index, Error> {
        let repo = Repository::open(path)?;

        repo.find_remote("origin")?
            .fetch(&[self.branch], None, None)?;

        let last_commit = self.find_last_commit(&repo)?;
        let reference = repo.find_reference("FETCH_HEAD")?;
        let fetched_commit = reference.peel_to_commit()?;
        let index =
            repo.merge_commits(&last_commit, &fetched_commit, Some(&MergeOptions::new()))?;

        return Ok(index);
    }

    pub fn check(&self) {
        let repo_path = Path::new(self.path);

        if !repo_path.exists() {
            self.clone();
            return;
        }

        if repo_path.exists() && repo_path.is_dir() {
            self.reset(repo_path);
            let idx = match self.pull(repo_path) {
                Ok(idx) => idx,
                Err(e) => panic!("Failed to pull: {}", e),
            };
        }
    }
}

fn main() {
    let currencies = Repo {
        url: "https://github.com/datasets/currency-codes",
        path: "./resources/currency-codes",
        branch: "master",
    };

    currencies.check();
}

Но пока клон и сброс работают, похоже, что pull не работает.

Что я делаю не так?

1 Ответ

1 голос
/ 09 ноября 2019

Репо git2-rs имеет ожидающий PR , который добавляет пример получения. Я немного адаптировал его здесь, чтобы показать, как выполнить ускоренную перемотку вперед, поскольку именно это вы и ищете:

fn fast_forward(&self, path: &Path) -> Result<(), Error> {
    let repo = Repository::open(path)?;

    repo.find_remote("origin")?
        .fetch(&[self.branch], None, None)?;

    let fetch_head = repo.find_reference("FETCH_HEAD")?;
    let fetch_commit = repo.reference_to_annotated_commit(&fetch_head)?;
    let analysis = repo.merge_analysis(&[&fetch_commit])?;
    if analysis.0.is_up_to_date() {
        Ok(())
    } else if analysis.0.is_fast_forward() {
        let refname = format!("refs/heads/{}", self.branch);
        let mut reference = repo.find_reference(&refname)?;
        reference.set_target(fetch_commit.id(), "Fast-Forward")?;
        repo.set_head(&refname)?;
        repo.checkout_head(Some(git2::build::CheckoutBuilder::default().force()))
    } else {
        Err(Error::from_str("Fast-forward only!"))
    }
}

pub fn check(&self) {
    ...
    if repo_path.exists() && repo_path.is_dir() {
        self.reset(repo_path);
        if let Err(e) = self.fast_forward(repo_path) {
            panic!("Failed to pull: {}", e)
        }
    }
}

Автор, конечно же, автор оригинала. Вы также можете проверить его на случай нетривиального слияния, т. Е. Когда локальное дерево грязное.

...