简体   繁体   English

如何使用 Rust git2 crate 执行“git pull”?

[英]How to perform “git pull” with the Rust git2 crate?

The git2 crate doesn't have direct way to perform "git pull" action. git2 crate 没有直接的方法来执行“git pull”操作。

I've seen this question and tried to do it the same way ( playground ):我已经看到了这个问题并尝试以相同的方式( 操场):

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();
}

But while clone and reset work, it looks like pull doesn't.但是虽然克隆重置工作,但看起来pull没有。

What am I do wrong?我做错了什么?

The git2-rs repo does have a pending PR which adds a pull example. git2-rs repo 确实有一个待处理的 PR ,它添加了一个 pull 示例。 I adapted it a bit here to show how to do a fast-forward since that's what you are looking for:我在这里对其进行了一些调整,以展示如何进行快进,因为这正是您要寻找的:

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)
        }
    }
}

The credit is original author's of course.功劳当然是原作者的。 You can also check it out for nontrivial merge case, ie when the local tree is dirty.您还可以检查它是否存在非平凡的合并情况,即当本地树脏时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM