How to do a git add --force *
with libgit2 in Rust?
I tried the following code from the documentation:
use git2::{Index, IndexAddOption, Repository};
let repo = Repository::open("/path/to/a/repo").expect("failed to open");
let mut index = repo.index().expect("cannot get the Index file");
index.add_all(["*"].iter(), IndexAddOption::DEFAULT, None);
index.write();
and it seems to work. Then I replaced IndexAddOption::DEFAULT
to IndexAddOption::FORCE
and I get the following error (example from a test on the Linux Kernel source code):
Error { code: -1, klass: 10, message: "invalid path: 'arch/i386/'" }', src/main.rs:58:14
What I understand is that when I use FORCE
, it will add "files" that are "non-standard" (like binaries or even directories) for git. That's why it is trying to add a directory and raises the invalid path error.
I just would like to implement a git add --force *
using libgit2 API in Rust. Any suggestions?
Thank you.
CodePudding user response:
It is possible to define a callback function IndexMatchedPath
like in this example.
Using this function raises the same error with a precision that it is from git.status_file()
. In fact, on Line 42 of the previous example, we have this line:
let status = repo.status_file(path).unwrap();
First, to remove the error, we can check if path
is a directory or not. We can ignore if it is a directory like mentioned in the documentation of git2::IndexMatchedPath
:
Return 0 to confirm the operation on the item, > 0 to skip the item, and < 0 to abort the scan.
However, we still have the error with if path.is_dir() { 1 }else {...}
. Hence, just extracting the string with path.to_str().unwrap()
and testing if it ends_with("/")
seems to work. Our function looks like this:
let cb = &mut |path: &Path, _matched_spec: &[u8]| -> i32 {
if path.to_str().unwrap().ends_with("/") { 1 }else{
let status = self.repository.status_file(path).unwrap();
...
};
Now that we removed the error, we move to the implementation of --force
. In the example, it checks the status of the files to add:
let ret = if status.contains(git2::Status::WT_MODIFIED)
|| status.contains(git2::Status::WT_NEW)
It adds modified or new files (more info here). So, in addition of modified and new files, we can include ignored files with git2::Status::IGNORED
:
let ret = if status.contains(git2::Status::WT_MODIFIED)
|| status.contains(git2::Status::WT_NEW)
|| status.contains(git2::Status::IGNORED)
So now, we use IndexAddOption::FORCE
and cb
:
index.add_all(["*"].iter(), IndexAddOption::FORCE, Some(cb as &mut git2::IndexMatchedPath));