Git2恢复暂存文件

rhfm7lfc  于 2022-09-21  发布在  Git
关注(0)|答案(1)|浏览(190)

我正在尝试建立一个业余爱好应用程序,为Git提供一个用户界面。我正在尝试执行相当于git restore --staged <file>的操作。在文件是新添加到索引中的情况下,下面的*似乎成功地执行了正确的操作,因此我可以只从索引中删除它,但我不确定如何处理文件以前已添加到索引中并已被修改的情况。我对Git和C的理解都很有限,这使得我很难自己解决这个问题。

use git2;

fn main() {
    let repo = git2::Repository::open("myrepo").unwrap();
    let mut index = repo.index().unwrap();
    let statuses = repo.statuses(None).unwrap();
    let file_status_entry = statuses.get(0).unwrap();
    let ct_path = std::path::Path::new(file_status_entry.path().unwrap());
    let file_status = file_status_entry.status();
    if file_status.is_index_new() {
        index.remove(ct_path, 0).unwrap();
    } else {
        // not sure what to do here
        index.remove(ct_path, 0).unwrap();
    }
    index.write().unwrap();
}
jobtbby3

jobtbby31#

git restore命令是...很复杂。因此,无论您使用什么语言和库,准确地模拟它也是很复杂的。但是,如果您将自己限制为git restore的行为的一个示例(例如,git restore --staged),那么事情就简单了。

我不熟悉这里的Rust库版本,所以我只能告诉您CGIT如何处理git restore --staged *path*。该操作“目标”是将某个路径从某个源提交复制到Git的索引中。使用--staged时,源提交默认为HEAD(除非用--source覆盖)。此操作不会影响工作树(当然,除非您还添加了--worktree)。

铁 rust 当量将相当于:

  • 打开并读取存储库(如您所做的);
  • 打开并读取索引(就像您所做的那样),但也获得了锁;
  • 打开并阅读Current Commit的树以找到给定路径。

在这一点上,您已经准备好接受逻辑。注意:对于git restore,参数不是路径名,而是路径规范,这需要在各种情况下迭代所有匹配的路径名(例如,git restore --staged "*")。这可能会影响下面的逻辑(如果您正在git restore-ing */foo,并且有六个目录可能具有foo,但其中只有四个目录确实具有foo,则其他两个目录应该不会出现“不匹配”的情况)。如果您只处理单个路径名称,则您的工作将得到简化,如下所示。

  • 如果命名文件存在于当前提交中,请将其数据复制到该路径下的索引中,删除所有未合并的索引项(非零分段项),然后继续执行“重写索引”步骤。

  • 否则(命名文件*不存在于本次提交中):

  • 如果指定的文件存在于索引中,请删除所有这些条目并继续执行重写索引步骤。

  • 否则,错误-退出,并出现样式不匹配错误(error: pathspec 'foo' did not match any file(s) know to git)。

一旦您对单个文件(没有路径规范,只列出了一个文件)或所有适当的文件(GLOBING或其他文件)执行了此操作,如果您已经更新了索引,现在就可以将其放回原处了。这包括将新的内容索引写入在第二个初始步骤中作为锁获得的index.lock文件,将其刷新到磁盘(如果操作系统具有fsync,请确保将其fsync),并对其进行重命名以释放锁并将其放在适当的位置作为索引。

还要记住,要处理任何git worktree add复杂情况(这些情况会导致不同的默认索引文件)和/或GIT_INDEX_FILE环境复杂情况。图书馆可能会(也可能不会)涵盖这些内容。

相关问题