git-sync-filtered 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Merge 42
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-sync-filtered
3
+ Version: 0.1.0
4
+ Summary: Sync filtered commits from private to public repository
5
+ Author-email: Your Name <you@example.com>
6
+ License: MIT
7
+ Keywords: git,filter,sync,repo
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: click>=8.0
19
+ Requires-Dist: gitpython>=3.1
20
+ Requires-Dist: git-filter-repo>=2.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Requires-Dist: ruff; extra == "dev"
24
+ Requires-Dist: mypy; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # git-sync-filtered
28
+
29
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Merge-42/git-sync-filtered?style=social)
30
+ ![Python versions](https://img.shields.io/pypi/pyversions/git-sync-filtered)
31
+ ![License](https://img.shields.io/pypi/l/git-sync-filtered)
32
+
33
+ A thin wrapper around [git-filter-repo](https://github.com/newren/git-filter-repo) for syncing filtered commits from a private repository to a public repository.
34
+
35
+ ## Overview
36
+
37
+ 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.
38
+
39
+ ## Installation
40
+
41
+ ### uv (recommended)
42
+
43
+ ```bash
44
+ uv tool install git+https://github.com/Merge-42/git-sync-filtered
45
+ ```
46
+
47
+ ### uvx (run without installing)
48
+
49
+ ```bash
50
+ uvx git+https://github.com/Merge-42/git-sync-filtered \
51
+ --private git@github.com:org/private.git \
52
+ --public git@github.com:org/public.git \
53
+ --keep src \
54
+ --keep docs
55
+ ```
56
+
57
+ ### pip
58
+
59
+ ```bash
60
+ pip install git+https://github.com/Merge-42/git-sync-filtered
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ git-sync-filtered \
67
+ --private git@github.com:org/private.git \
68
+ --public git@github.com:org/public.git \
69
+ --keep src \
70
+ --keep docs
71
+ ```
72
+
73
+ ### Using a paths file
74
+
75
+ Create a file with paths to keep (one per line, lines starting with `#` are comments):
76
+
77
+ ```text
78
+ src
79
+ docs
80
+ README.md
81
+ ```
82
+
83
+ ```bash
84
+ git-sync-filtered \
85
+ --private git@github.com:org/private.git \
86
+ --public git@github.com:org/public.git \
87
+ --keep-from-file paths.txt
88
+ ```
89
+
90
+ ## Options
91
+
92
+ | Option | Description | Default |
93
+ | ------------------ | --------------------------------------------- | --------------- |
94
+ | `--private` | Private repo path or URL | Required |
95
+ | `--public` | Public repo path or URL | Required |
96
+ | `--keep` | Paths to keep (specify multiple) | Required |
97
+ | `--keep-from-file` | File containing paths to keep | - |
98
+ | `--sync-branch` | Sync branch name | `upstream/sync` |
99
+ | `--main-branch` | Main branch name | `main` |
100
+ | `--private-branch` | Private branch to sync from | `main` |
101
+ | `--dry-run` | Show what would happen without making changes | `false` |
102
+ | `--merge` | Merge into main branch after sync | `false` |
103
+ | `--force` | Force push | `false` |
104
+
105
+ ## How It Works
106
+
107
+ 1. Clones the private repository
108
+ 2. Runs git-filter-repo to filter to only the specified paths
109
+ 3. Pushes filtered commits to the public repository's sync branch
110
+ 4. Optionally merges the sync branch into main
111
+
112
+ The sync branch can then be merged into main manually or with `--merge`.
113
+
114
+ ## Workflow
115
+
116
+ ```mermaid
117
+ flowchart LR
118
+ A[Private Repo<br/>private-branch] -->|clone & filter| B[git-sync-filtered]
119
+ B -->|push| C[Public Repo<br/>sync-branch]
120
+ C -->|"merge<br/>(manual or with --merge)"| D[Public Repo<br/>main-branch]
121
+ ```
122
+
123
+ ## Requirements
124
+
125
+ - Python 3.10+
126
+ - git >= 2.36.0
127
+
128
+ ---
129
+
130
+ Sponsored by [Merge 42](https://merge42.com)
@@ -0,0 +1,104 @@
1
+ # git-sync-filtered
2
+
3
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Merge-42/git-sync-filtered?style=social)
4
+ ![Python versions](https://img.shields.io/pypi/pyversions/git-sync-filtered)
5
+ ![License](https://img.shields.io/pypi/l/git-sync-filtered)
6
+
7
+ A thin wrapper around [git-filter-repo](https://github.com/newren/git-filter-repo) for syncing filtered commits from a private repository to a public repository.
8
+
9
+ ## Overview
10
+
11
+ 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.
12
+
13
+ ## Installation
14
+
15
+ ### uv (recommended)
16
+
17
+ ```bash
18
+ uv tool install git+https://github.com/Merge-42/git-sync-filtered
19
+ ```
20
+
21
+ ### uvx (run without installing)
22
+
23
+ ```bash
24
+ uvx git+https://github.com/Merge-42/git-sync-filtered \
25
+ --private git@github.com:org/private.git \
26
+ --public git@github.com:org/public.git \
27
+ --keep src \
28
+ --keep docs
29
+ ```
30
+
31
+ ### pip
32
+
33
+ ```bash
34
+ pip install git+https://github.com/Merge-42/git-sync-filtered
35
+ ```
36
+
37
+ ## Usage
38
+
39
+ ```bash
40
+ git-sync-filtered \
41
+ --private git@github.com:org/private.git \
42
+ --public git@github.com:org/public.git \
43
+ --keep src \
44
+ --keep docs
45
+ ```
46
+
47
+ ### Using a paths file
48
+
49
+ Create a file with paths to keep (one per line, lines starting with `#` are comments):
50
+
51
+ ```text
52
+ src
53
+ docs
54
+ README.md
55
+ ```
56
+
57
+ ```bash
58
+ git-sync-filtered \
59
+ --private git@github.com:org/private.git \
60
+ --public git@github.com:org/public.git \
61
+ --keep-from-file paths.txt
62
+ ```
63
+
64
+ ## Options
65
+
66
+ | Option | Description | Default |
67
+ | ------------------ | --------------------------------------------- | --------------- |
68
+ | `--private` | Private repo path or URL | Required |
69
+ | `--public` | Public repo path or URL | Required |
70
+ | `--keep` | Paths to keep (specify multiple) | Required |
71
+ | `--keep-from-file` | File containing paths to keep | - |
72
+ | `--sync-branch` | Sync branch name | `upstream/sync` |
73
+ | `--main-branch` | Main branch name | `main` |
74
+ | `--private-branch` | Private branch to sync from | `main` |
75
+ | `--dry-run` | Show what would happen without making changes | `false` |
76
+ | `--merge` | Merge into main branch after sync | `false` |
77
+ | `--force` | Force push | `false` |
78
+
79
+ ## How It Works
80
+
81
+ 1. Clones the private repository
82
+ 2. Runs git-filter-repo to filter to only the specified paths
83
+ 3. Pushes filtered commits to the public repository's sync branch
84
+ 4. Optionally merges the sync branch into main
85
+
86
+ The sync branch can then be merged into main manually or with `--merge`.
87
+
88
+ ## Workflow
89
+
90
+ ```mermaid
91
+ flowchart LR
92
+ A[Private Repo<br/>private-branch] -->|clone & filter| B[git-sync-filtered]
93
+ B -->|push| C[Public Repo<br/>sync-branch]
94
+ C -->|"merge<br/>(manual or with --merge)"| D[Public Repo<br/>main-branch]
95
+ ```
96
+
97
+ ## Requirements
98
+
99
+ - Python 3.10+
100
+ - git >= 2.36.0
101
+
102
+ ---
103
+
104
+ Sponsored by [Merge 42](https://merge42.com)
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ git-sync-filtered - Sync filtered commits from private to public repo
4
+
5
+ Usage:
6
+ git-sync-filtered --private /path/to/private --public /path/to/public --keep src --keep docs
7
+ """
8
+
9
+ from git_sync_filtered.cli import main
10
+
11
+ if __name__ == "__main__":
12
+ main()
@@ -0,0 +1,77 @@
1
+ import click
2
+
3
+ from git_sync_filtered.sync import sync
4
+
5
+
6
+ @click.command()
7
+ @click.option("--private", required=True, help="Private repo path or URL")
8
+ @click.option("--public", required=True, help="Public repo path or URL")
9
+ @click.option("--keep", multiple=True, help="Paths to keep (can specify multiple)")
10
+ @click.option(
11
+ "--keep-from-file",
12
+ type=click.Path(exists=True),
13
+ help="File containing paths to keep (one per line)",
14
+ )
15
+ @click.option("--sync-branch", default="upstream/sync", help="Sync branch name")
16
+ @click.option("--main-branch", default="main", help="Main branch name")
17
+ @click.option("--private-branch", default="main", help="Private branch to sync from")
18
+ @click.option(
19
+ "--dry-run", is_flag=True, help="Show what would happen without making changes"
20
+ )
21
+ @click.option("--merge", is_flag=True, help="Merge into main branch after sync")
22
+ @click.option("--force", is_flag=True, help="Force push")
23
+ def main(
24
+ private,
25
+ public,
26
+ keep,
27
+ keep_from_file,
28
+ sync_branch,
29
+ main_branch,
30
+ private_branch,
31
+ dry_run,
32
+ merge,
33
+ force,
34
+ ):
35
+ """Sync filtered commits from private to public repository."""
36
+
37
+ try:
38
+ result = sync(
39
+ private=private,
40
+ public=public,
41
+ keep=keep,
42
+ keep_from_file=keep_from_file,
43
+ sync_branch=sync_branch,
44
+ main_branch=main_branch,
45
+ private_branch=private_branch,
46
+ dry_run=dry_run,
47
+ merge=merge,
48
+ force=force,
49
+ )
50
+ except ValueError as e:
51
+ raise click.ClickException(str(e))
52
+
53
+ click.echo("=== Git Filter Sync ===")
54
+ click.echo(f"Private: {private}")
55
+ click.echo(f"Public: {public}")
56
+ click.echo(f"Keep: {result['paths_to_keep']}")
57
+ click.echo(f"Sync to: {sync_branch}")
58
+ click.echo()
59
+
60
+ if dry_run:
61
+ click.echo(f"[git-sync] DRY RUN - Would push to {sync_branch}")
62
+ click.echo()
63
+ click.echo("Commits that would be pushed:")
64
+ for commit in result["dry_run_commits"]:
65
+ click.echo(commit)
66
+ else:
67
+ click.echo()
68
+ click.echo(f"=== Synced to {sync_branch} ===")
69
+
70
+ if merge and not dry_run:
71
+ if result["merge_success"]:
72
+ click.echo(f"[git-sync] Merged and pushed to {main_branch}")
73
+ else:
74
+ click.echo("[git-sync] Merge conflict! Please resolve manually:")
75
+
76
+ click.echo()
77
+ click.echo("Done!")
@@ -0,0 +1,128 @@
1
+ import os
2
+ from itertools import filterfalse
3
+ from pathlib import Path
4
+ from tempfile import TemporaryDirectory
5
+ from typing import Optional
6
+
7
+ import git
8
+ from git_filter_repo import FilteringOptions, RepoFilter
9
+
10
+
11
+ def read_paths_from_file(path: Path) -> list[str]:
12
+ lines = (line.strip() for line in path.read_text().splitlines())
13
+ return list(filterfalse(lambda line: line.startswith("#") or not line, lines))
14
+
15
+
16
+ def collect_paths_to_keep(
17
+ keep: tuple[str, ...], keep_from_file: Optional[str]
18
+ ) -> list[str]:
19
+ paths_to_keep = set(keep)
20
+
21
+ if keep_from_file:
22
+ paths_to_keep.update(read_paths_from_file(Path(keep_from_file)))
23
+
24
+ return sorted(list(paths_to_keep))
25
+
26
+
27
+ def run_filter_repo(repo_path: str, paths_to_keep: list[str]) -> None:
28
+ old_cwd = os.getcwd()
29
+ os.chdir(repo_path)
30
+
31
+ try:
32
+ argv = ["--force", "--partial"]
33
+ for path in paths_to_keep:
34
+ argv.extend(["--path", path])
35
+
36
+ filter_args = FilteringOptions.parse_args(argv, error_on_empty=False)
37
+ repo_filter = RepoFilter(filter_args)
38
+ repo_filter.run()
39
+ finally:
40
+ os.chdir(old_cwd)
41
+
42
+
43
+ def push_to_remote(
44
+ repo: git.Repo,
45
+ public_url: str,
46
+ sync_branch: str,
47
+ private_branch: str,
48
+ force: bool = False,
49
+ dry_run: bool = False,
50
+ ) -> list[str]:
51
+ if "public" not in repo.remotes:
52
+ repo.create_remote("public", public_url)
53
+ else:
54
+ repo.remote("public").set_url(public_url)
55
+
56
+ repo.remote("public").fetch()
57
+
58
+ if dry_run:
59
+ commits = []
60
+ for commit in repo.iter_commits(private_branch):
61
+ commits.append(f" {commit.hexsha[:8]} {commit.summary}")
62
+ return commits
63
+ else:
64
+ refspec = f"refs/heads/{private_branch}:refs/heads/{sync_branch}"
65
+ repo.remote("public").push(refspec=refspec, force=force)
66
+ return []
67
+
68
+
69
+ def merge_into_main(
70
+ repo: git.Repo,
71
+ main_branch: str,
72
+ sync_branch: str,
73
+ ) -> bool:
74
+ repo.heads[main_branch].checkout()
75
+
76
+ try:
77
+ sync_head = repo.heads[sync_branch]
78
+ repo.index.merge_commit(sync_head, msg=f"Merge branch '{sync_branch}'")
79
+
80
+ repo.remote("public").push(
81
+ refspec=f"refs/heads/{main_branch}:refs/heads/{main_branch}"
82
+ )
83
+ return True
84
+ except git.GitCommandError:
85
+ return False
86
+
87
+
88
+ def sync(
89
+ private: str,
90
+ public: str,
91
+ keep: tuple[str, ...],
92
+ keep_from_file: Optional[str],
93
+ sync_branch: str,
94
+ main_branch: str,
95
+ private_branch: str,
96
+ dry_run: bool,
97
+ merge: bool,
98
+ force: bool,
99
+ ):
100
+ paths_to_keep = collect_paths_to_keep(keep, keep_from_file)
101
+
102
+ if not paths_to_keep:
103
+ raise ValueError("At least one --keep path or --keep-from-file required")
104
+
105
+ with TemporaryDirectory(prefix="git-sync-") as work_dir:
106
+ work_dir_path = Path(work_dir)
107
+ private_clone = work_dir_path / "private"
108
+ private_repo = git.Repo.clone_from(private, str(private_clone))
109
+
110
+ run_filter_repo(str(private_clone), paths_to_keep)
111
+
112
+ dry_run_commits = push_to_remote(
113
+ private_repo, public, sync_branch, private_branch, force, dry_run
114
+ )
115
+
116
+ if merge and not dry_run:
117
+ success = merge_into_main(private_repo, main_branch, sync_branch)
118
+ return {
119
+ "paths_to_keep": paths_to_keep,
120
+ "dry_run_commits": dry_run_commits,
121
+ "merge_success": success,
122
+ }
123
+
124
+ return {
125
+ "paths_to_keep": paths_to_keep,
126
+ "dry_run_commits": dry_run_commits,
127
+ "merge_success": None,
128
+ }
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-sync-filtered
3
+ Version: 0.1.0
4
+ Summary: Sync filtered commits from private to public repository
5
+ Author-email: Your Name <you@example.com>
6
+ License: MIT
7
+ Keywords: git,filter,sync,repo
8
+ Classifier: Development Status :: 3 - Alpha
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Requires-Python: >=3.10
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: click>=8.0
19
+ Requires-Dist: gitpython>=3.1
20
+ Requires-Dist: git-filter-repo>=2.0
21
+ Provides-Extra: dev
22
+ Requires-Dist: pytest; extra == "dev"
23
+ Requires-Dist: ruff; extra == "dev"
24
+ Requires-Dist: mypy; extra == "dev"
25
+ Dynamic: license-file
26
+
27
+ # git-sync-filtered
28
+
29
+ ![GitHub Repo stars](https://img.shields.io/github/stars/Merge-42/git-sync-filtered?style=social)
30
+ ![Python versions](https://img.shields.io/pypi/pyversions/git-sync-filtered)
31
+ ![License](https://img.shields.io/pypi/l/git-sync-filtered)
32
+
33
+ A thin wrapper around [git-filter-repo](https://github.com/newren/git-filter-repo) for syncing filtered commits from a private repository to a public repository.
34
+
35
+ ## Overview
36
+
37
+ 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.
38
+
39
+ ## Installation
40
+
41
+ ### uv (recommended)
42
+
43
+ ```bash
44
+ uv tool install git+https://github.com/Merge-42/git-sync-filtered
45
+ ```
46
+
47
+ ### uvx (run without installing)
48
+
49
+ ```bash
50
+ uvx git+https://github.com/Merge-42/git-sync-filtered \
51
+ --private git@github.com:org/private.git \
52
+ --public git@github.com:org/public.git \
53
+ --keep src \
54
+ --keep docs
55
+ ```
56
+
57
+ ### pip
58
+
59
+ ```bash
60
+ pip install git+https://github.com/Merge-42/git-sync-filtered
61
+ ```
62
+
63
+ ## Usage
64
+
65
+ ```bash
66
+ git-sync-filtered \
67
+ --private git@github.com:org/private.git \
68
+ --public git@github.com:org/public.git \
69
+ --keep src \
70
+ --keep docs
71
+ ```
72
+
73
+ ### Using a paths file
74
+
75
+ Create a file with paths to keep (one per line, lines starting with `#` are comments):
76
+
77
+ ```text
78
+ src
79
+ docs
80
+ README.md
81
+ ```
82
+
83
+ ```bash
84
+ git-sync-filtered \
85
+ --private git@github.com:org/private.git \
86
+ --public git@github.com:org/public.git \
87
+ --keep-from-file paths.txt
88
+ ```
89
+
90
+ ## Options
91
+
92
+ | Option | Description | Default |
93
+ | ------------------ | --------------------------------------------- | --------------- |
94
+ | `--private` | Private repo path or URL | Required |
95
+ | `--public` | Public repo path or URL | Required |
96
+ | `--keep` | Paths to keep (specify multiple) | Required |
97
+ | `--keep-from-file` | File containing paths to keep | - |
98
+ | `--sync-branch` | Sync branch name | `upstream/sync` |
99
+ | `--main-branch` | Main branch name | `main` |
100
+ | `--private-branch` | Private branch to sync from | `main` |
101
+ | `--dry-run` | Show what would happen without making changes | `false` |
102
+ | `--merge` | Merge into main branch after sync | `false` |
103
+ | `--force` | Force push | `false` |
104
+
105
+ ## How It Works
106
+
107
+ 1. Clones the private repository
108
+ 2. Runs git-filter-repo to filter to only the specified paths
109
+ 3. Pushes filtered commits to the public repository's sync branch
110
+ 4. Optionally merges the sync branch into main
111
+
112
+ The sync branch can then be merged into main manually or with `--merge`.
113
+
114
+ ## Workflow
115
+
116
+ ```mermaid
117
+ flowchart LR
118
+ A[Private Repo<br/>private-branch] -->|clone & filter| B[git-sync-filtered]
119
+ B -->|push| C[Public Repo<br/>sync-branch]
120
+ C -->|"merge<br/>(manual or with --merge)"| D[Public Repo<br/>main-branch]
121
+ ```
122
+
123
+ ## Requirements
124
+
125
+ - Python 3.10+
126
+ - git >= 2.36.0
127
+
128
+ ---
129
+
130
+ Sponsored by [Merge 42](https://merge42.com)
@@ -0,0 +1,12 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ git_sync_filtered/__main__.py
5
+ git_sync_filtered/cli.py
6
+ git_sync_filtered/sync.py
7
+ git_sync_filtered.egg-info/PKG-INFO
8
+ git_sync_filtered.egg-info/SOURCES.txt
9
+ git_sync_filtered.egg-info/dependency_links.txt
10
+ git_sync_filtered.egg-info/entry_points.txt
11
+ git_sync_filtered.egg-info/requires.txt
12
+ git_sync_filtered.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-sync-filtered = git_sync_filtered.__main__:main
@@ -0,0 +1,8 @@
1
+ click>=8.0
2
+ gitpython>=3.1
3
+ git-filter-repo>=2.0
4
+
5
+ [dev]
6
+ pytest
7
+ ruff
8
+ mypy
@@ -0,0 +1 @@
1
+ git_sync_filtered
@@ -0,0 +1,44 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "git-sync-filtered"
7
+ version = "0.1.0"
8
+ description = "Sync filtered commits from private to public repository"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ license = { text = "MIT" }
12
+ authors = [{ name = "Your Name", email = "you@example.com" }]
13
+ keywords = ["git", "filter", "sync", "repo"]
14
+ classifiers = [
15
+ "Development Status :: 3 - Alpha",
16
+ "Intended Audience :: Developers",
17
+ "License :: OSI Approved :: MIT License",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.10",
20
+ "Programming Language :: Python :: 3.11",
21
+ "Programming Language :: Python :: 3.12",
22
+ ]
23
+
24
+ dependencies = ["click>=8.0", "gitpython>=3.1", "git-filter-repo>=2.0"]
25
+
26
+ [project.optional-dependencies]
27
+ dev = ["pytest", "ruff", "mypy"]
28
+
29
+ [project.scripts]
30
+ git-sync-filtered = "git_sync_filtered.__main__:main"
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["."]
34
+ include = ["git_sync_filtered*"]
35
+
36
+ [tool.ruff]
37
+ line-length = 100
38
+ target-version = "py310"
39
+
40
+ [tool.mypy]
41
+ python_version = "3.10"
42
+
43
+ [dependency-groups]
44
+ dev = ["pytest>=9.0.2"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+