Skip to content

Commit 5f6c2fb

Browse files
committed
status quo test that shows gitoxide has the same limitation as git (#301)
Question is how we should solve it or if at all… . After all it would mean that files that are accidentally excluded by git would be included by gitoxide. So best to leave it like this and fix it once git fixes it.
1 parent 36fa167 commit 5f6c2fb

File tree

4 files changed

+91
-3
lines changed

4 files changed

+91
-3
lines changed

git-worktree/src/fs/cache/state.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,12 @@ impl Ignore {
102102
if mapping.pattern.is_negative() {
103103
dir_match = Some(match_);
104104
} else {
105+
// Note that returning here is wrong if this pattern _was_ preceeded by a negative pattern that
106+
// didn't match the directory, but would match now.
107+
// Git does it similarly so we do too even though it's incorrect.
108+
// To fix this, one would probably keep track of whether there was a preceeding negative pattern, and
109+
// if so we check the path in full and only use the dir match if there was no match, similar to the negative
110+
// case above whose fix fortunately won't change the overall result.
105111
return match_.into();
106112
}
107113
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:24f605623efc49819d1b30c52fe22da8f94f2d267e8030ec9bc3b9b845801f76
3+
size 9220
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
set -eu -o pipefail
3+
4+
git init -q
5+
6+
mkdir -p tld tld/sd
7+
cat <<EOF >.gitignore
8+
# directory exclude
9+
tld/
10+
11+
!tld/file
12+
EOF
13+
14+
cat <<EOF >tld/.gitignore
15+
sd/
16+
!sd/
17+
18+
!file
19+
EOF
20+
21+
git check-ignore -vn --stdin 2>&1 <<EOF >git-check-ignore.baseline || :
22+
tld
23+
tld/
24+
tld/file
25+
tld/sd
26+
tld/sd/
27+
EOF
28+

git-worktree/tests/worktree/fs/cache/ignore_and_attributes.rs

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,62 @@ impl<'a> Iterator for IgnoreExpectations<'a> {
3333
}
3434
}
3535

36+
#[test]
37+
fn special_exclude_cases_we_handle_differently() {
38+
let dir = git_testtools::scripted_fixture_repo_read_only("make_special_exclude_case.sh").unwrap();
39+
let git_dir = dir.join(".git");
40+
41+
let mut buf = Vec::new();
42+
let case = git_glob::pattern::Case::Sensitive;
43+
let state = git_worktree::fs::cache::State::for_add(
44+
Default::default(),
45+
git_worktree::fs::cache::state::Ignore::new(
46+
Default::default(),
47+
git_attributes::MatchGroup::from_git_dir(&git_dir, None, &mut buf).unwrap(),
48+
None,
49+
case,
50+
),
51+
);
52+
let mut cache = fs::Cache::new(&dir, state, case, buf, Default::default());
53+
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline")).unwrap();
54+
let expectations = IgnoreExpectations {
55+
lines: baseline.lines(),
56+
};
57+
for (relative_entry, source_and_line) in expectations {
58+
let (source, line, pattern) = source_and_line.expect("every value is matched");
59+
assert_eq!(
60+
pattern, "tld/",
61+
"each entry matches on the main directory exclude, ignoring negations entirely"
62+
);
63+
assert_eq!(line, 2);
64+
assert_eq!(source, ".gitignore");
65+
66+
let relative_path = git_path::from_byte_slice(relative_entry);
67+
let is_dir = dir.join(&relative_path).metadata().ok().map(|m| m.is_dir());
68+
69+
let platform = cache
70+
.at_entry(relative_entry, is_dir, |oid, buf| {
71+
Err(std::io::Error::new(std::io::ErrorKind::Other, "unreachable"))
72+
})
73+
.unwrap();
74+
let match_ = platform.matching_exclude_pattern().expect("match all values");
75+
let is_excluded = platform.is_excluded();
76+
77+
match relative_entry.as_ref() {
78+
b"tld" | b"tld/" | b"tld/file" | b"tld/sd" | b"tld/sd/" => {
79+
assert_eq!(match_.pattern.to_string(), "tld/");
80+
}
81+
_ => unreachable!(),
82+
}
83+
}
84+
}
85+
3686
#[test]
3787
fn check_against_baseline() -> crate::Result {
3888
let dir = git_testtools::scripted_fixture_repo_read_only("make_ignore_and_attributes_setup.sh")?;
3989
let worktree_dir = dir.join("repo");
4090
let git_dir = worktree_dir.join(".git");
4191
let mut buf = Vec::new();
42-
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
4392
let user_exclude_path = dir.join("user.exclude");
4493
assert!(user_exclude_path.is_file());
4594

@@ -66,9 +115,11 @@ fn check_against_baseline() -> crate::Result {
66115
);
67116
let mut cache = fs::Cache::new(&worktree_dir, state, case, buf, attribute_files_in_index);
68117

69-
for (relative_entry, source_and_line) in (IgnoreExpectations {
118+
let baseline = std::fs::read(git_dir.parent().unwrap().join("git-check-ignore.baseline"))?;
119+
let expectations = IgnoreExpectations {
70120
lines: baseline.lines(),
71-
}) {
121+
};
122+
for (relative_entry, source_and_line) in expectations {
72123
let relative_path = git_path::from_byte_slice(relative_entry);
73124
let is_dir = worktree_dir.join(&relative_path).metadata().ok().map(|m| m.is_dir());
74125

0 commit comments

Comments
 (0)