unstage file
harilet opened this issue · 6 comments
I was trying to unstage files. I can add file fine by using
let mut index = repo.index().unwrap();
index.add_path(Path::new(&path)).unwrap();
I saw we can use the remove_path like this
let mut index = repo.index().unwrap();
index.remove_path(Path::new(&path)).unwrap();
index.write().unwrap();
but this deletes file not remove changes

what can I do?
and I saw this remove but the 2th parameter stage is an int but have no more detail
https://docs.rs/git2/latest/git2/struct.Index.html#method.remove
The 2nd parameter is usually 0 for the main index. Other numbers are used when dealing with merge conflicts and such.
@ehuss ok I understand that now.
so what can I do to just unstage changes from a file, any ideas?
It's index.remove(path, 0)
@ehuss
similar to remove_path remove also just deletes the file from the index not unstage the changes
let mut index = repo.index().unwrap();
index.remove(Path::new(&path),0).unwrap();
index.write().unwrap();
I want to unstage changes not delete the file from the index
Oh, sorry, I misremembered how that worked. There are a few different approaches to emulate restore --staged, which is generally a pretty complicated command. One is to use reset_default, and another is to rewrite the index based on the head tree.
For example:
use git2::*;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let repo = Repository::init("repo")?;
// Add a file and commit it.
std::fs::write("repo/foo.txt", "")?;
let mut index = repo.index()?;
index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?;
index.write()?;
let tree_id = index.write_tree()?;
let sig = repo.signature()?;
repo.commit(
Some("HEAD"),
&sig,
&sig,
"test",
&repo.find_tree(tree_id)?,
&[],
)?;
// Modify the file and stage it.
std::fs::write("repo/foo.txt", "this is a test")?;
let mut index = repo.index()?;
index.add_all(["*"].iter(), git2::IndexAddOption::DEFAULT, None)?;
index.write()?;
std::process::Command::new("git")
.arg("status")
.current_dir("repo")
.status()?;
// Unstage the file
let head = repo.head()?;
let commit = head.peel_to_commit()?;
repo.reset_default(Some(commit.as_object()), &["foo.txt"])?;
std::process::Command::new("git")
.arg("status")
.current_dir("repo")
.status()?;
Ok(())
}The other approach writing the index is a bit more complicated, and I may not recommend it:
// Unstage the file
let mut index = repo.index()?;
let head = repo.head()?;
let commit = head.peel_to_commit()?;
let head_tree = commit.tree()?;
let tree_entry = head_tree.get_path(std::path::Path::new("foo.txt"))?;
let mut index_entry = index.get_path(std::path::Path::new("foo.txt"), 0).expect("is staged");
// May need to investigate if other index entry fields should be updated...
index_entry.id = tree_entry.id();
index_entry.mode = tree_entry.filemode() as u32;
index.add(&index_entry)?;
index.write()?;