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 <newren@gmail.com>
pull/43/head
Elijah Newren 5 years ago
parent b1a35a3057
commit f9ebe6a3f7

@ -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`

@ -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,

Loading…
Cancel
Save