【问题标题】:How to get the behaviour of `git checkout ...` in Rust git2如何在 Rust git2 中获取 `git checkout ...` 的行为
【发布时间】:2019-08-04 01:52:54
【问题描述】:

我正在使用 Rust git2 crate 来克隆这样的 Git 存储库

use git2::Repository;

fn main() {
    let repo = Repository::clone(
        "https://github.com/rossmacarthur/dotfiles",
        "dotfiles"
     ).expect("failed to clone repository");

     repo.checkout("mybranch");  // need something like this.
}

我希望能够签出一个分支、一个提交或一个标签。

我已经查看了以下文档,但仍然不确定使用哪种方法

我可以执行以下操作,但它只会更改文件

let object = repo
    .revparse_single("mybranch")
    .expect("failed to find identifier");
repo.checkout_tree(&object, None)
    .expect(&format!("failed to checkout '{:?}'", object));

如果我进行重置,它会更改 HEAD 但不会更改当前分支

repo.reset(&object, git2::ResetType::Soft, None)
    .expect(&format!("failed to checkout '{:?}'", object));

【问题讨论】:

    标签: git rust checkout libgit2


    【解决方案1】:

    下面的例子是 Rust v1.34 和 git2 v0.8。

    结帐一个分支:

    use git2::*;
    
    fn main() {
        let repo = Repository::clone(
            "https://github.com/rossmacarthur/dotfiles",
            "dotfiles"
        ).expect("failed to clone repository");
    
        let branch_name = "my_branch";
    
        let head = repo.head().unwrap();
        let oid = head.target().unwrap();
        let commit = repo.find_commit(oid).unwrap();
    
        let branch = repo.branch(
            branch_name,
            &commit,
            false,
        );
    
        let obj = repo.revparse_single(&("refs/heads/".to_owned() + 
            branch_name)).unwrap();
    
        repo.checkout_tree(
            &obj,
            None
        );
    
        repo.set_head(&("refs/heads/".to_owned() + branch_name));
    }
    

    检查提交:

    use git2::*;
    
    fn main() {
        let repo = Repository::clone(
            "https://github.com/rossmacarthur/dotfiles",
            "dotfiles"
        ).expect("failed to clone repository");
    
        let my_oid_str = "9411953f92d100f767e6de6325b17afae5231779";
    
        let oid = Oid::from_str(my_oid_str).unwrap();
        let commit = repo.find_commit(oid).unwrap();
    
        let branch = repo.branch(
            my_oid_str,
            &commit,
            false,
        );
    
        let obj = repo.revparse_single(&("refs/heads/".to_owned() + my_oid_str)).unwrap(); 
    
        repo.checkout_tree(
            &obj,
            None,
        );
    
        repo.set_head(&("refs/heads/".to_owned() + my_oid_str));
    
    }
    

    要签出标签,请尝试以下操作:

    use git2::*;
    
    fn main() {
        // No relation to the example project below.
        // It looks interesting and it has tags!
        let repo = Repository::clone(
            "https://github.com/narke/colorForth.git",
            "colorforth"
        ).expect("failed to clone repository");
    
        let tag_name = "v2012";
    
        let references = repo.references().unwrap();
    
        for reference in references {
            let _reference = reference.unwrap();
    
            if _reference.is_tag() == true {
                let tag = _reference.peel_to_tag().unwrap();
                if tag.name().unwrap() == tag_name {
                    let target_oid = tag.target().unwrap().id();
                    let commit = repo.find_commit(target_oid).unwrap();
    
                    let branch = repo.branch(
                        tag_name,
                        &commit,
                        false,
                    );
    
                    let obj = repo.revparse_single(&("refs/heads/".to_owned() + tag_name)).unwrap();
    
                    repo.checkout_tree(
                        &obj,
                        None,
                    );
    
                    repo.set_head(&("refs/heads/".to_owned() + tag_name)); 
                }
            }
    
        }
    }
    

    我敢打赌,通常会有更好的方法,但这个问题几个月来一直没有答案,这就是我刚才想出来的方法。

    【讨论】:

    • 我更新的帖子完全解决了 OP 的问题。赞成票表示赞赏。我什至没有足够的积分来评论其他人的帖子,就像OP那样,所以我现在可以让他们成功回答了这个问题。如果对此问题表现出任何兴趣,我将努力使答案更加地道。
    • 在检查提交的示例中,正确使用的方法是 set_head_detached() - set_head() 需要一个引用名称,如 refs/heads/masterHEAD(但提交哈希不是 ref )。所以正确的方法是repo.set_head_detached(oid);
    【解决方案2】:

    使用更新版本的git2 (v0.13.18):

    use git2::Repository;
    
    fn main() {
        let repo = Repository::clone("https://github.com/rossmacarthur/dotfiles", "/tmp/dots")
            .expect("Failed to clone repo");
    
        let refname = "master"; // or a tag (v0.1.1) or a commit (8e8128)
        let (object, reference) = repo.revparse_ext(refname).expect("Object not found");
        
        repo.checkout_tree(&object, None)
            .expect("Failed to checkout");
    
        match reference {
            // gref is an actual reference like branches or tags
            Some(gref) => repo.set_head(gref.name().unwrap()),
            // this is a commit, not a reference
            None => repo.set_head_detached(object.id()),
        }
        .expect("Failed to set HEAD");
    }
    
    

    注意checkout_tree 只设置工作树的内容,set_head 只设置HEAD。只运行其中一个会使目录处于脏状态。

    【讨论】:

    • 谢谢,这样干净多了!
    【解决方案3】:

    我认为repo.set_head("mybranch") 是您正在寻找的。更多信息请见here

    【讨论】:

    • 1. repo.set_head("refs/heads/mybranch"), 2. 这不会改变工作目录中的文件
    猜你喜欢
    • 1970-01-01
    • 2017-05-24
    • 2016-08-29
    • 1970-01-01
    • 2018-12-03
    • 2013-01-07
    • 2012-09-16
    • 1970-01-01
    • 2023-01-31
    相关资源
    最近更新 更多