From f9ebe6a3f757b34eb1b17d536ae812a4d515aee6 Mon Sep 17 00:00:00 2001 From: Elijah Newren Date: Thu, 26 Dec 2019 13:17:55 -0800 Subject: [PATCH] filter-repo: avoid clobbering files whose names differ in case only git fast-import, in an attempt to be friendly, allows the same file to be specified multiple times within a commit and just takes the last version of the file listed. It determines whether files are the same via fspathncmp, which is defined differently depending on the setting of core.ignorecase. Unfortunately, this means that if someone is trying to do filtering of history and using a broken (case-insensitive) filesystem and the history they are filtering has some paths that differed in name only, then fast-import will delete whichever of the "colliding" files is listed first. Avoid these problems by just turning off core.ignorecase while fast-import is running. This will prevent silently modifying the repo in an unexpected way. Users on such filesystems may have difficulty checking out commits with files which differ in case only, but that is a separate problem for them to deal with after rewriting history. Signed-off-by: Elijah Newren --- Documentation/git-filter-repo.txt | 2 +- git-filter-repo | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Documentation/git-filter-repo.txt b/Documentation/git-filter-repo.txt index c1cd293..6e3c60a 100644 --- a/Documentation/git-filter-repo.txt +++ b/Documentation/git-filter-repo.txt @@ -942,7 +942,7 @@ sequence that more accurately reflects what filter-repo runs is: 1. Verify we're in a fresh clone 2. `git fetch -u . refs/remotes/origin/*:refs/heads/*` 3. `git remote rm origin` - 4. `git fast-export --show-original-ids --reference-excluded-parents --fake-missing-tagger --signed-tags=strip --tag-of-filtered-object=rewrite --use-done-feature --no-data --reencode=yes --mark-tags --all | filter | git fast-import --force --quiet` + 4. `git fast-export --show-original-ids --reference-excluded-parents --fake-missing-tagger --signed-tags=strip --tag-of-filtered-object=rewrite --use-done-feature --no-data --reencode=yes --mark-tags --all | filter | git -c core.ignorecase=false fast-import --force --quiet` 5. `git update-ref --no-deref --stdin`, fed with a list of refs to nuke, and a list of replace refs to delete, create, or update. 6. `git reset --hard` 7. `git reflog expire --expire=now --all` diff --git a/git-filter-repo b/git-filter-repo index 51a91de..5675c67 100755 --- a/git-filter-repo +++ b/git-filter-repo @@ -3534,7 +3534,8 @@ class RepoFilter(object): def _setup_output(self): if not self._args.dry_run: location = ['-C', self._args.target] if self._args.target else [] - fip_cmd = ['git'] + location + ['fast-import', '--force', '--quiet'] + fip_cmd = ['git'] + location + ['-c', 'core.ignorecase=false', + 'fast-import', '--force', '--quiet'] if self._args.state_branch: target_marks_file = self._load_marks_file(b'target-marks') fip_cmd.extend([b'--export-marks='+target_marks_file,