Description
When there is a gitignore entry with a trailing slash, git_index_add_all
will add symlinks that match the gitignore patterns on Windows but not other platforms.
Reproduction steps
The following Rust program demonstrates the problem. Sorry for only including a Rust reproduction, hopefully it is easy to see the equivalent C api calls (it is mostly 1:1). I couldn't figure out how to build a project with Visual Studio linking to libgit2 (if there are docs somewhere on how to do that, I'd be happy to make a C example).
use git2::*;
use std::fs;
fn main() {
// Create a repo with a gitignore file and a symlink.
fs::create_dir_all("repo/src").unwrap();
fs::write("repo/src/samplefile", "test").unwrap();
#[cfg(windows)]
{
std::os::windows::fs::symlink_dir("src", "repo/src2").unwrap();
}
#[cfg(unix)]
{
std::os::unix::fs::symlink("src", "repo/src2").unwrap();
}
fs::write("repo/.gitignore", "/src2/").unwrap();
let repo = Repository::init("repo").unwrap();
// Add all and commit.
let mut index = repo.index().unwrap();
index
.add_all(["*"], git2::IndexAddOption::DEFAULT, None)
.unwrap();
index.write().unwrap();
let tree_id = index.write_tree().unwrap();
let tree_oid = repo.find_tree(tree_id).unwrap();
let sig = repo.signature().unwrap();
let oid = repo
.commit(Some("HEAD"), &sig, &sig, "initial commit", &tree_oid, &[])
.unwrap();
// Check the contents of the commit.
let commit = repo.find_commit(oid).unwrap();
let mut names = Vec::new();
commit
.tree()
.unwrap()
.walk(TreeWalkMode::PreOrder, |_name, entry| {
names.push(entry.name().unwrap().to_string());
TreeWalkResult::Ok
})
.unwrap();
names.sort();
assert_eq!(names, [".gitignore", "samplefile", "src"]);
}
In this example, there is a file src/samplefile
and a symlink src2 -> src
. The .gitignore
has a pattern /src2/
intending to prevent src2
from being added.
Expected behavior
git_index_add_all
will only add .gitignore
and src/samplefile
.
Actual behavior
On Windows, it also adds the src2
symlink, causing the final assert to fail.
This seems to only happen with patterns with a trailing slash. A summary of the the gitignore pattern behavior:
/src2/
andsrc2/
fail on Windows./src2
andsrc2
work as expected on all platforms.
I've also tested with core.symlinks=true
or false
, it doesn't seem to affect it.
Version of libgit2 (release number or SHA1)
Operating system(s) tested
Windows, macOS, Linux