> ## Documentation Index
> Fetch the complete documentation index at: https://newren-git-filter-repo.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Path-Based Filtering

> Rename and restructure files and directories in repository history

## Overview

Path-based filtering allows you to rename files and directories throughout your repository's entire history. This is essential when restructuring projects, merging repositories, or correcting naming conventions.

## Path Renaming Basics

### Simple Rename

Rename a directory throughout history:

```bash theme={null}
# Rename tools/ to scripts/
git filter-repo --path-rename tools/:scripts/
```

> [!NOTE]
>
> Trailing slashes are optional for directories:
>
> * `tools/:scripts/` (with slash)
> * `tools:scripts` (without slash)
>
> Both work identically.

### Multiple Renames

Perform several renames in one operation:

```bash theme={null}
git filter-repo \
  --path-rename cmds:tools \
  --path-rename src/scripts/:tools/
```

> [!WARNING]
>
> **Order Matters!**
>
> Renames are applied in the order specified. The command above:
>
> 1. First renames `cmds` → `tools`
> 2. Then renames `src/scripts/` → `tools/`
>
> Reversing the order could give different results.

## Advanced Renaming

### Merge Directories

Rename multiple directories to the same location:

**Before**

```
cmds/
  run.sh
src/scripts/
  build.sh
tools/
  deploy.sh
```

**Command**

```bash theme={null}
git filter-repo \
  --path-rename cmds/:tools/ \
  --path-rename src/scripts/:tools/
```

**After**

```
tools/
  run.sh
  build.sh
  deploy.sh
```

### Handle Naming Conflicts

If two files would collide when renamed, specify an additional rename:

```bash theme={null}
# If both cmds/release.sh and src/scripts/release.sh exist
git filter-repo \
  --path-rename cmds/release.sh:tools/old_release.sh \
  --path-rename cmds/:tools/ \
  --path-rename src/scripts/:tools/
```

> [!NOTE]
>
> Specific file renames should come **before** directory renames to prevent conflicts.

## Combining Filtering and Renaming

### Filter Then Rename

Path renaming doesn't filter paths - combine with `--path` for that:

**Wrong**

```bash theme={null}
# This keeps only src/main/ - tools/ is never included!
git filter-repo \
  --path src/main/ \
  --path-rename tools/:scripts/
```

**Right**

```bash theme={null}
# Keep both src/main/ and tools/, then rename tools/
git filter-repo \
  --path src/main/ \
  --path tools/ \
  --path-rename tools/:scripts/
```

### Create New Structure

Restructure your repository layout:

```bash theme={null}
# Move sources/ to src/main/ and keep only that
git filter-repo \
  --path-rename sources/:src/main/ \
  --path src/main/
```

> [!WARNING]
>
> Order is critical! The command above:
>
> 1. First renames `sources/` → `src/main/`
> 2. Then filters to keep only `src/main/`
>
> Reversing these steps would result in an empty repository.

## Restructuring Projects

### Flatten Directory Structure

Move files from nested directories to root:

```bash theme={null}
# Move src/main/java/com/example/ to src/
git filter-repo \
  --path-rename src/main/java/com/example/:src/
```

### Create Nested Structure

Add directory layers:

```bash theme={null}
# Move all files under src/legacy/
git filter-repo --path-rename :src/legacy/
```

Empty string before `:` means repository root.

### Module Reorganization

Reorganize a monorepo into separate modules:

```bash theme={null}
git filter-repo \
  --path-rename api/:services/api/ \
  --path-rename web/:services/web/ \
  --path-rename common/:lib/shared/
```

## Merging Repositories

### Prepare Repository for Merge

When merging multiple repositories, prefix each with a unique directory:

**Repo A**

```bash theme={null}
cd repo-a
git filter-repo --to-subdirectory-filter project-a/
```

**Repo B**

```bash theme={null}
cd repo-b
git filter-repo --to-subdirectory-filter project-b/
```

**Merge**

```bash theme={null}
cd repo-a
git remote add repo-b ../repo-b
git fetch repo-b
git merge repo-b/main --allow-unrelated-histories
```

Result:

```
project-a/
  (original repo-a contents)
project-b/
  (original repo-b contents)
```

### Split Monorepo

Extract a module and rename it:

```bash theme={null}
# Extract auth module and make it the root
git filter-repo \
  --path modules/auth/ \
  --path-rename modules/auth/:
```

## Regex-Based Renaming

Use regex for complex renaming patterns:

```bash theme={null}
# Rename files like foo/bar/baz.text to bar/foo/baz.txt
git filter-repo --paths-from-file - <<EOF
regex:(.*)/([^/]*)/([^/]*)\.text$==>
\2/\1/\3.txt
EOF
```

> [!NOTE]
>
> **Regex Syntax:**
>
> * `(.*)` - Capture group (any characters)
> * `[^/]*` - Non-slash characters
> * `\1`, `\2`, `\3` - Back-references to captured groups
>
> See [Python regex syntax](https://docs.python.org/3/library/re.html) for details.

## Complex Renaming Examples

### Normalize File Extensions

```bash theme={null}
# Create rename rules
cat > renames.txt <<EOF
regex:(.*/)?([^/]*)\.text$==>
\1\2.txt
regex:(.*/)?([^/]*)\.jpeg$==>
\1\2.jpg
EOF

git filter-repo --paths-from-file renames.txt
```

### Add Version Prefix to Directories

```bash theme={null}
# Rename api/ to api-v1/, web/ to web-v1/, etc.
cat > renames.txt <<EOF
api/==>api-v1/
web/==>web-v1/
shared/==>shared-v1/
EOF

git filter-repo --paths-from-file renames.txt
```

### Reorganize by Language

Group files by programming language:

```bash theme={null}
cat > renames.txt <<EOF
glob:*.py==>python/
glob:*.js==>javascript/
glob:*.java==>java/
glob:*.go==>golang/
EOF

git filter-repo --paths-from-file renames.txt
```

## Renaming with Callbacks

For extremely complex renames, use Python callbacks:

```bash theme={null}
git filter-repo --filename-callback '
  if filename.startswith(b"src/"):
    return b"lib/" + filename[4:]
  elif filename.endswith(b".txt"):
    return filename[:-4] + b".md"
  else:
    return filename
'
```

See [Advanced Filtering](https://newren-git-filter-repo.mintlify.site/guides/advanced-filtering.md) for more on callbacks.

## Important Considerations

> [!WARNING]
>
> **Collision Detection**
>
> If renames cause two different files to have the same path, filter-repo will error:
>
> ```
> Error: File collision detected: path/to/file.txt
> ```
>
> Resolve by renaming one of the conflicting files first.

> [!NOTE]
>
> **Silent Overwrites**
>
> If you rename a path to one that already exists, the existing file is silently overwritten. Use `--analyze` to check for potential conflicts first.

> [!TIP]
>
> **Test First**
>
> Use `--dry-run` to preview changes:
>
> ```bash theme={null}
> git filter-repo --dry-run \
>   --path-rename old/:new/
> ```
>
> This shows what would happen without modifying the repository.

## Partial Renames

Rename paths only on specific branches:

```bash theme={null}
git filter-repo \
  --refs feature-branch \
  --path-rename old/:new/
```

> [!WARNING]
>
> This uses `--partial` mode, which mixes old and new history. Use carefully!

## Verification

After renaming, verify the results:

```bash theme={null}
# Check that old paths are gone
git log --all --oneline -- old/path/

# Check that new paths exist
git log --all --oneline -- new/path/

# Verify specific file was renamed
git log --follow --all -- new/path/file.txt
```

## Next Steps

* Learn about [Content-Based Filtering](https://newren-git-filter-repo.mintlify.site/guides/content-based-filtering.md)
* Explore [Commit Message Rewriting](https://newren-git-filter-repo.mintlify.site/guides/commit-message-rewriting.md)
* See [Library Usage](https://newren-git-filter-repo.mintlify.site/guides/library-usage.md) for programmatic control


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.