You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
72 lines
2.3 KiB
Plaintext
72 lines
2.3 KiB
Plaintext
5 years ago
|
#!/usr/bin/env python3
|
||
|
|
||
|
"""
|
||
|
This is a simple program that will delete files from history which match
|
||
|
current gitignore rules, while also:
|
||
|
1) pruning commits which become empty
|
||
|
2) pruning merge commits which become degenerate and have no changes
|
||
|
relative to its remaining relevant parent
|
||
|
3) rewriting commit hashes in commit messages to reference new commit IDs.
|
||
|
"""
|
||
|
|
||
|
"""
|
||
|
Please see the
|
||
|
***** API BACKWARD COMPATIBILITY CAVEAT *****
|
||
|
near the top of git-filter-repo.
|
||
|
"""
|
||
|
|
||
|
import argparse
|
||
|
import os
|
||
|
import subprocess
|
||
|
try:
|
||
|
import git_filter_repo as fr
|
||
|
except ImportError:
|
||
|
raise SystemExit("Error: Couldn't find git_filter_repo.py. Did you forget to make a symlink to git-filter-repo named git_filter_repo.py or did you forget to put the latter in your PYTHONPATH?")
|
||
|
|
||
|
class CheckIgnores:
|
||
|
def __init__(self):
|
||
|
self.ignored = set()
|
||
|
self.okay = set()
|
||
|
|
||
|
cmd = 'git check-ignore --stdin --verbose --non-matching --no-index'
|
||
|
self.check_ignore_process = subprocess.Popen(cmd.split(),
|
||
|
stdin=subprocess.PIPE,
|
||
|
stdout=subprocess.PIPE)
|
||
|
|
||
|
def __del__(self):
|
||
|
if self.check_ignore_process:
|
||
|
self.check_ignore_process.stdin.close()
|
||
|
|
||
|
def get_ignored(self, filenames):
|
||
|
ignored = set()
|
||
|
for name in filenames:
|
||
|
if name in self.ignored:
|
||
|
ignored.add(name)
|
||
|
elif name in self.okay:
|
||
|
continue
|
||
|
else:
|
||
|
self.check_ignore_process.stdin.write(name+b'\n')
|
||
|
self.check_ignore_process.stdin.flush()
|
||
|
result = self.check_ignore_process.stdout.readline().rstrip(b'\n')
|
||
|
(rest, pathname) = result.split(b"\t")
|
||
|
if name != pathname:
|
||
|
raise SystemExit("Error: Passed {} but got {}".format(name, pathname))
|
||
|
if rest == b'::':
|
||
|
self.okay.add(name)
|
||
|
else:
|
||
|
self.ignored.add(name)
|
||
|
ignored.add(name)
|
||
|
|
||
|
return ignored
|
||
|
|
||
|
def skip_ignores(self, commit, metadata):
|
||
|
filenames = [x.filename for x in commit.file_changes]
|
||
|
bad = self.get_ignored(filenames)
|
||
|
commit.file_changes = [x for x in commit.file_changes
|
||
|
if x.filename not in bad]
|
||
|
|
||
|
checker = CheckIgnores()
|
||
|
args = fr.FilteringOptions.default_options()
|
||
|
filter = fr.RepoFilter(args, commit_callback=checker.skip_ignores)
|
||
|
filter.run()
|