### Renormalize Line Endings and Add .gitattributes Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example shows how to renormalize end-of-line characters in a Git repository and add a `.gitattributes` file. It suggests using the `dos2unix` filter and the `insert-beginning` contrib script for this purpose. ```bash contrib/filter-repo-demos/lint-history dos2unix [edit .gitattributes] contrib/filter-repo-demos/insert-beginning .gitattributes ``` -------------------------------- ### Python Refname Callback Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Provides a Python callback example for the --refname-callback argument, demonstrating how to prepend a prefix to a fully qualified refname. It takes a 'refname' (bytestring) and returns the modified 'refname'. ```python import os def refname_callback(refname): # Change e.g. refs/heads/master to refs/heads/prefix-master rdir,rpath = os.path.split(refname) return rdir + b"/prefix-" + rpath ``` -------------------------------- ### Filter files with include and exclude rules using filename-callback Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Implements both include and exclude rules for filenames in a single git filter-repo run using a Python callback. Example includes all files under src/ directory except src/README.md by returning None to exclude and filename to include. ```bash git filter-repo --filename-callback ' if filename == b"src/README.md": return None if filename.startswith(b"src/"): return filename return None' ``` -------------------------------- ### Extract Library from Repo using git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example demonstrates how to extract a specific subdirectory from a Git repository and place it at a different location within the repository's structure, without moving it to the root. It uses `--path` to specify the directory to keep and `--path-rename` to define the new location. ```git git filter-repo \ --path src/some-folder/some-feature/ \ --path-rename src/some-folder/some-feature/:src/ ``` -------------------------------- ### Python Callback Function Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Demonstrates how to define a Python callback function for the --foo-callback argument. The function receives a parameter 'foo' and should modify and return it. Note that git-filter-repo uses bytestrings for all operations. ```python def foo_callback(foo): BODY ``` -------------------------------- ### Python Name Callback Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Shows a Python callback for the --name-callback argument to replace specific byte sequences in a name. The callback takes a 'name' (bytestring) and returns a modified 'name'. ```python def name_callback(name): return name.replace(b"Wiliam", b"William") ``` -------------------------------- ### Handle special characters in author names with encoding Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Properly handles multi-byte UTF-8 characters like accents and umlauts in author names by encoding normal Python strings to bytestrings. Example changes author name to include special characters and updates email based on current email match. ```bash git filter-repo --refs main~5..main --commit-callback ' if commit.author_email = b"example@test.com": commit.author_name = "Raphaël González".encode() commit.author_email = b"rgonzalez@test.com" ' ``` -------------------------------- ### Python Email Callback Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Illustrates a Python callback for the --email-callback argument to perform a byte string replacement. The function takes an 'email' (bytestring) and returns the modified 'email'. ```python def email_callback(email): return email.replace(b".cm", b".com") ``` -------------------------------- ### Convert NFD filenames to NFC using iconv utility Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Converts filenames from NFD (decomposed) UTF-8 normalization to NFC (composed) form using system iconv utility. Useful for Mac repositories where filename encoding normalization may have changed historically. Spawns iconv subprocess for each filename. ```bash git filter-repo --filename-callback ' try: return subprocess.check_output("iconv -f utf-8-mac -t utf-8".split(), input=filename) except: return filename ' ``` -------------------------------- ### Purge Large List of Files using git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example shows how to remove a large number of files from a Git repository. The filenames are provided in a file, one per line, and `git filter-repo` is used with `--invert-paths` and `--paths-from-file` to exclude these files from the history. ```git git filter-repo --invert-paths --paths-from-file ../DELETED_FILENAMES.txt ``` -------------------------------- ### Add Files to Root Commits using git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example demonstrates how to add existing files to the root of commits, specifically for root commits (commits with no parents). It utilizes the `--commit-callback` option to specify the files and their hashes. Alternatively, the `insert-beginning` contrib script can be used. ```git git filter-repo --commit-callback "if not commit.parents: commit.file_changes += [ FileChange(b'M', b'README.md', b'$(git hash-object -w '/path/to/existing/README.md')', b'100644'), FileChange(b'M', b'src/.gitignore', b'$(git hash-object -w '/home/myusers/mymodule.gitignore')', b'100644')" ``` ```bash mv /path/to/existing/README.md README.md mv /home/myusers/mymodule.gitignore src/.gitignore insert-beginning --file README.md insert-beginning --file src/.gitignore ``` -------------------------------- ### Python Message Callback Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Demonstrates a Python callback for the --message-callback argument to append a 'Signed-off-by' line and substitute email patterns in a message. It takes a 'message' (bytestring) and returns the modified 'message'. Requires the 're' module. ```python import re def message_callback(message): if b"Signed-off-by:" not in message: message += b"\nSigned-off-by: Me My " return re.sub(b"[Ee]-?[Mm][Aa][Ii][Ll]", b"email", message) ``` -------------------------------- ### Convert NFD filenames to NFC using Python unicodedata Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Converts filenames from NFD to NFC normalization using Python's built-in unicodedata module instead of spawning external processes. More efficient alternative that handles UTF-8 encoding/decoding internally without system dependencies. ```bash git filter-repo --filename-callback ' import unicodedata try: return bytearray(unicodedata.normalize('NFC', filename.decode('utf-8')), 'utf-8') except: return filename ' ``` -------------------------------- ### Keep Files from Specific Branches using git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example demonstrates how to retain only the files that existed on two specified branches, deleting all others from history. It involves listing files from each branch, combining and sorting them, and then using `--paths-from-file` to filter the repository. ```bash git ls-tree -r ${BRANCH1} >../my-files git ls-tree -r ${BRANCH2} >>../my-files sort ../my-files | uniq >../my-relevant-files git filter-repo --paths-from-file ../my-relevant-files ``` -------------------------------- ### Replace PNG files with compressed versions using file-info-callback Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Use git-filter-repo with a file-info-callback to replace poorly compressed PNG blob IDs with their optimized versions. Checks filename and original blob ID, then returns the new blob ID to rewrite history with compressed files. ```bash git filter-repo --file-info-callback ' if filename == b"resources/foo.png" and blob_id == b"edf570fde099c0705432a389b96cb86489beda09": blob_id = b"9cce52ae0806d695956dcf662cd74b497eaa7b12" if filename == b"resources/bar.png" and blob_id == b"644f7c55e1a88a29779dc86b9ff92f512bf9bc11": blob_id = b"88b02e9e45c0a62db2f1751b6c065b0c2e538820" return (filename, mode, blob_id) ' ``` -------------------------------- ### Fix multi-line strings in blob-callback with textwrap.dedent Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Use Python's textwrap.dedent to properly handle multi-line strings in git-filter-repo callbacks without unwanted leading spaces. Removes indentation while maintaining proper formatting in the resulting blob data. ```bash git filter-repo --blob-callback ' import textwrap blob.data = bytes(textwrap.dedent("""\ This is the new file that I am replacing every blob with. It is great.\n"""), "utf-8") ' ``` -------------------------------- ### Python Filename Callback Example Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt Illustrates a Python callback for the --filename-callback argument, showing how to remove files, keep them, or rename them based on path conditions. It takes a 'filename' (bytestring) and returns either None (to remove), the original filename (to keep), or a new filename (to rename). ```python def filename_callback(filename): if b"/src/" in filename: # Remove all files with a directory named "src" in their path # (except when "src" appears at the toplevel). return None elif filename.startswith(b"tools/"): # Rename tools/ -> scripts/misc/ return b"scripts/misc/" + filename[6:] else: # Keep the filename and do not rename it return filename ``` -------------------------------- ### Filter Git Repo: Rename Path with Collision Handling Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt This example demonstrates renaming a specific file and then renaming directories, resolving potential naming collisions by renaming a specific file first to avoid conflicts when multiple paths are renamed to the same destination. ```bash git filter-repo --path-rename cmds/run_release.sh:tools/do_release.sh \ --path-rename cmds/:tools/ \ --path-rename src/scripts/:tools/ ``` -------------------------------- ### Identify repository corruption with fsck Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Uses git fsck utility to identify corrupt objects in repository including commits and trees. Output shows error types such as missing space before date in author/committer lines and duplicate file entries in trees. First step in handling repository corruption before applying filters. ```bash git fsck --full ``` -------------------------------- ### Remove trailing spaces and convert CRLF to LF Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Removes all trailing spaces and tabs at the end of lines in non-binary files and converts CRLF line endings to LF. Uses regex pattern matching with git filter-repo to perform text replacement across the entire repository history. ```bash git filter-repo --replace-text <(echo 'regex:[\r\t ]+(\n|$)==>\n') ``` -------------------------------- ### Fix Corrupt Git Commit Object Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This process involves printing a corrupt commit object to a temporary file, editing it to fix errors (e.g., missing spaces), and then using `git replace` to create a replacement reference. Finally, `git filter-repo --proceed` is run to apply the changes permanently. This method is used for manually correcting corrupted commit objects. ```shell git cat-file -p 166f57b3fbe31257100361ecaf735f305b533b21 >tmp # ... edit tmp to fix the corrupt object ... git replace -f 166f57b3fbe31257100361ecaf735f305b533b21 $(git hash-object -t commit -w tmp) rm tmp git filter-repo --proceed ``` -------------------------------- ### Remove directory from repository history Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Removes an entire directory and its contents from git repository history using path specification with invert-paths flag. Example removes the node_modules/electron/dist/ directory. ```bash git filter-repo --path node_modules/electron/dist/ --invert-paths ``` -------------------------------- ### Replace Words in Commit Messages using git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This example shows how to replace specific words within all commit messages in a Git repository's history. It utilizes the `--message-callback` option with a Python string replacement function. ```git git filter-repo --message-callback 'return message.replace(b"stuff", b"task")' ``` -------------------------------- ### Simplify linting history with lint-history script Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/converting-from-filter-branch.md Uses the contrib script 'lint-history' to simplify applying formatters like clang-format. It provides a more concise way to specify which files to process and the command to run, leveraging filter-repo's library capabilities for efficiency and additional features. ```shell lint-history --relevant 'return filename.endswith(b".c")' \ clang-format -style=file -i ``` -------------------------------- ### Parse Arguments and Initialize Filter Source: https://context7.com/newren/git-filter-repo/llms.txt Parses command-line arguments with the '--force' flag, which is necessary for non-fresh clones. It then initializes a RepoFilter with the parsed arguments and a commit callback function. ```python #!/usr/bin/env python3 import git_filter_repo as fr def my_commit_callback(commit, metadata): # Callback function implementation pass args = fr.FilteringOptions.parse_args(['--force']) filter = fr.RepoFilter(args, commit_callback=my_commit_callback) filter.run() ``` -------------------------------- ### Run clang-format on C files using git filter-repo callback Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/converting-from-filter-branch.md Applies clang-format to C files using the git filter-repo --file-info-callback. This approach is more involved but handles file content and metadata separately. It writes file contents to a temporary file, formats it, and then reads it back to update the blob. ```shell git filter-repo --file-info-callback ' if not filename.endswith(b".c"): return (filename, mode, blob_id) # no changes contents = value.get_contents_by_identifier(blob_id) tmpfile = os.path.basename(filename) with open(tmpfile, "wb") as f: f.write(contents) subprocess.check_call(["clang-format", "-style=file", "-i", filename]) with open(filename, "rb") as f: contents = f.read() new_blob_id = value.insert_file_with_contents(contents) return (filename, mode, new_blob_id) ' ``` -------------------------------- ### Analyze Repository with git-filter-repo Source: https://context7.com/newren/git-filter-repo/llms.txt Generate comprehensive reports on repository structure including file sizes, paths, extensions, and rename history. This command creates multiple analysis files in a specified report directory to help understand repository composition and history. ```bash git filter-repo --analyze git filter-repo --analyze --report-dir=/tmp/repo-analysis ``` -------------------------------- ### Remove Filenames with Backslashes Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md This snippet demonstrates how to remove all files whose filenames contain a backslash character. It utilizes the `--filename-callback` option of `git filter-repo` to inspect and conditionally keep or discard filenames based on the presence of the backslash. ```shell git filter-repo --filename-callback 'return None if b'\' in filename else filename' ``` -------------------------------- ### Replace Text in Git Repo: BFG vs. git-filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/converting-from-bfg-repo-cleaner.md Demonstrates how to replace sensitive text content within a Git repository. BFG uses a jar file and a specific command, while git-filter-repo offers a direct command-line interface. Note the difference in backslash/dollar sign usage for regex replacement strings. ```shell java -jar bfg.jar --replace-text passwords.txt my-repo.git ``` ```shell git filter-repo --replace-text passwords.txt ``` -------------------------------- ### Configure Filtering Options Programmatically in Python Source: https://context7.com/newren/git-filter-repo/llms.txt Shows how to set git-filter-repo filtering options using the API without command-line arguments. Configures options like force mode, partial filtering, reference replacement strategy, and empty commit pruning policies programmatically. ```python #!/usr/bin/env python3 import git_filter_repo as fr # Use default options and modify programmatically args = fr.FilteringOptions.default_options() args.force = True args.partial = False args.replace_refs = 'update-or-add' args.prune_empty = 'always' # or 'never' or 'auto' args.prune_degenerate = 'always' # No callbacks needed for simple path filtering filter = fr.RepoFilter(args) filter.run() ``` -------------------------------- ### Remove Commits by Author: git filter-branch vs git filter-repo Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/converting-from-filter-branch.md Shows how to remove commits authored by a specific person. Both examples are noted as potentially problematic, as they don't remove the changes themselves but rather reassign them. Git filter-repo provides a more Pythonic callback mechanism. ```shell git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_NAME" = "Darl McBribe" ]; then skip_commit "$@"; else git commit-tree "$@"; fi' HEAD ``` ```python git filter-repo --commit-callback ' if commit.author_name == b"Darl McBribe": commit.skip() ' ``` -------------------------------- ### Query Repository Information with GitUtils Helper Functions in Python Source: https://context7.com/newren/git-filter-repo/llms.txt Demonstrates GitUtils utility functions for retrieving Git repository metadata including refs with hashes, commit count, total objects, blob sizes in both packed and unpacked formats, and checking if repository is bare. Useful for repository analysis and statistics collection. ```python #!/usr/bin/env python3 import git_filter_repo as fr # Get repository information repo_path = b'.' # Get all refs (branches, tags) and their hashes refs = fr.GitUtils.get_refs(repo_path) for ref_name, ref_hash in refs.items(): print(f"{ref_name.decode()}: {ref_hash.decode()}") # Get commit count total_commits = fr.GitUtils.get_commit_count(repo_path) print(f"Total commits: {total_commits}") # Get total objects (blobs + trees) total_objects = fr.GitUtils.get_total_objects(repo_path) print(f"Total objects: {total_objects}") # Get blob sizes (unpacked and packed) unpacked_sizes, packed_sizes = fr.GitUtils.get_blob_sizes() for blob_id, size in list(unpacked_sizes.items())[:5]: print(f"Blob {blob_id.decode()}: {size} bytes (unpacked)") # Check if repository is bare is_bare = fr.GitUtils.is_repository_bare(repo_path) print(f"Is bare repository: {is_bare}") ``` -------------------------------- ### Remove files with specific extensions Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Removes all files matching a specific extension pattern from repository history. Two methods provided: using path-glob with invert-paths flag, or using a filename-callback Python function that returns None for matching files. ```bash git filter-repo --invert-paths --path-glob '*.xsa' ``` ```bash git filter-repo --filename-callback ' if filename.endswith(b".xsa"): return None return filename' ``` -------------------------------- ### Cache blob transformations using value.data Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/git-filter-repo.txt This callback enhances the previous example by caching transformation results in `value.data`. It checks if a `blob_id` has already been processed; if so, it returns the cached `new_blob_id`. Otherwise, it performs the transformation, stores the result, and then returns it. This prevents redundant processing of the same blob. ```shell git-filter-repo --file-info-callback ' if not filename.endswith(b".config"): # Make no changes to the file; return as-is return (filename, mode, blob_id) new_filename = filename[0:-7] + b".cfg" if blob_id in value.data: return (new_filename, mode, value.data[blob_id]) contents = value.get_contents_by_identifier(blob_id) new_contents = value.apply_replace_text(contents) new_blob_id = value.insert_file_with_contents(new_contents) value.data[blob_id] = new_blob_id return (new_filename, mode, new_blob_id) ' ``` -------------------------------- ### Modify committer information for recent commits Source: https://github.com/newren/git-filter-repo/blob/main/Documentation/examples-from-user-filed-issues.md Changes the committer name and email for a range of recent commits using commit-callback. Targets commits in a specific ref range (e.g., main~5..main) and modifies committer metadata while preserving commit content. ```bash git filter-repo --refs main~5..main --commit-callback ' commit.commiter_name = b"My Wonderful Self" commit.committer_email = b"my@self.org" ' ```