A thin wrapper around git-filter-repo for syncing filtered commits from a private repository to a public repository.
git-sync-filtered clones a private repository, filters it to only include specified paths using git-filter-repo, and pushes the result to a public repository's sync branch. This enables maintaining a public subset of a private repository while preserving commit history.
uv tool install git-sync-filteredpip install git-sync-filtereduvx git-sync-filtered \
--private git@github.com:org/private.git \
--public git@github.com:org/public.git \
--keep src \
--keep docsYou can use this workflow to sync from your private repo to a public repo when the private repo receives a push.
In your private repository, create .github/workflows/sync.yaml:
name: Sync to Public Repo
on:
push:
branches:
- main
jobs:
sync:
uses: Merge-42/git-sync-filtered/.github/workflows/sync.yaml@v0.1.5
with:
private_repo: ${{ github.repositoryUrl }}
public_repo: git@github.com:org/public.git
keep: src docs
merge: true
secrets:
GH_TOKEN: ${{ secrets.GH_PAT }}Required secrets:
GH_PAT- A GitHub Personal Access Token withreposcope (for pushing to the public repo)
Available inputs:
| Input | Description | Default |
|---|---|---|
private_repo |
Private repository URL | Required |
public_repo |
Public repository URL | Required |
keep |
Space-separated paths to keep | - |
keep_from_file |
File containing paths to keep | - |
sync_branch |
Sync branch name | upstream/sync |
main_branch |
Main branch name | main |
private_branch |
Private branch to sync from | main |
merge |
Merge into main after sync | false |
force |
Force push | false |
dry_run |
Dry run mode | false |
git-sync-filtered \
--private git@github.com:org/private.git \
--public git@github.com:org/public.git \
--keep src \
--keep docsCreate a file with paths to keep (one per line, lines starting with # are comments):
src
docs
README.md
git-sync-filtered \
--private git@github.com:org/private.git \
--public git@github.com:org/public.git \
--keep-from-file paths.txt| Option | Description | Default |
|---|---|---|
--private |
Private repo path or URL | Required |
--public |
Public repo path or URL | Required |
--keep |
Paths to keep (specify multiple) | Required |
--keep-from-file |
File containing paths to keep | - |
--sync-branch |
Sync branch name | upstream/sync |
--main-branch |
Main branch name | main |
--private-branch |
Private branch to sync from | main |
--dry-run |
Show what would happen without making changes | false |
--merge |
Merge into main branch after sync | false |
--force |
Force push | false |
- Clones the private repository
- Runs git-filter-repo to filter to only the specified paths
- Pushes filtered commits to the public repository's sync branch
- Optionally merges the sync branch into main
The sync branch can then be merged into main manually or with --merge.
flowchart LR
A[Private Repo<br/>private-branch] -->|clone & filter| B[git-sync-filtered]
B -->|push| C[Public Repo<br/>sync-branch]
C -->|"merge<br/>(manual or with --merge)"| D[Public Repo<br/>main-branch]
- Python 3.10+
- git >= 2.36.0
Sponsored by Merge 42