Skip to content

Commit cd91865

Browse files
author
Tom Nijboer
committed
feat: only add dirs to exclude if has files
1 parent 9248e15 commit cd91865

File tree

1 file changed

+21
-25
lines changed

1 file changed

+21
-25
lines changed

copier/_main.py

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,46 +1306,42 @@ def _apply_update(self) -> None: # noqa: C901
13061306
with local.cwd(subproject_top):
13071307
apply_cmd = git["apply", "--reject", "--exclude", self.answers_relpath]
13081308
ignored_files = git["status", "--ignored", "--porcelain"]()
1309-
# Parse .gitignore for directory-level patterns (robust)
1310-
1311-
def is_dir_pattern(pattern):
1312-
pattern = pattern.strip()
1313-
if not pattern or pattern.startswith("#"):
1314-
return False
1315-
# Matches foo/, foo/*, foo/**/, **/test/, **/test/*, etc.
1316-
return (
1317-
pattern.endswith("/")
1318-
or pattern.endswith("/*")
1319-
or pattern.endswith("/**/")
1320-
or re.match(r".*\*\*/.*", pattern)
1321-
)
1322-
13231309
gitignore_path = Path(subproject_top, ".gitignore")
13241310
dir_patterns = set()
13251311
if gitignore_path.exists():
13261312
with gitignore_path.open() as gitignore_file:
13271313
for line in gitignore_file:
13281314
line = line.strip()
1329-
if is_dir_pattern(line):
1330-
# Remove trailing slash or /* for matching
1315+
if not line or line.startswith("#"):
1316+
continue
1317+
# Matches foo/, foo/*, foo/**/, **/test/, **/test/*, etc.
1318+
if (
1319+
line.endswith("/")
1320+
or line.endswith("/*")
1321+
or line.endswith("/**/")
1322+
or re.match(r".*\*\*/.*", line)
1323+
):
13311324
cleaned = re.sub(r"(\/\*|\/\*\*\/|\/$)", "", line)
13321325
dir_patterns.add(cleaned)
1333-
# Build extra_exclude: only add files not covered by dir_patterns
1326+
# Single loop: process ignored files and build exclude lists
1327+
ignored_dirs = set()
13341328
extra_exclude = []
13351329
for filename in ignored_files.splitlines():
13361330
if filename.startswith("!! "):
13371331
fname = filename.split("!! ").pop()
1338-
# Check if file is in a directory pattern
1339-
if any(fname.startswith(p + "/") for p in dir_patterns):
1340-
continue # Skip, will be excluded by directory pattern
1341-
extra_exclude.append(fname)
1342-
# Add directory patterns first
1343-
for dir_pattern in dir_patterns:
1332+
matched_dir = False
1333+
for p in dir_patterns:
1334+
if fname == p or fname.startswith(p + "/"):
1335+
if fname.endswith("/"):
1336+
ignored_dirs.add(fname.rstrip("/"))
1337+
matched_dir = True
1338+
break
1339+
if not matched_dir:
1340+
extra_exclude.append(fname)
1341+
for dir_pattern in ignored_dirs:
13441342
apply_cmd = apply_cmd["--exclude", dir_pattern + "/*"]
1345-
# Add skip_if_exists patterns
13461343
for skip_pattern in map(self._render_string, self.all_skip_if_exists):
13471344
apply_cmd = apply_cmd["--exclude", skip_pattern]
1348-
# Add remaining specific files
13491345
for skip_pattern in extra_exclude:
13501346
apply_cmd = apply_cmd["--exclude", skip_pattern]
13511347
(apply_cmd << diff)(retcode=None)

0 commit comments

Comments
 (0)