git-omit 0.0.1__py3-none-any.whl

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.
git_omit/__init__.py ADDED
@@ -0,0 +1,6 @@
1
+ try:
2
+ from ._version import __version__
3
+ except ImportError:
4
+ __version__ = "0.0.0"
5
+
6
+ __all__ = ["__version__"]
git_omit/__main__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .cli import cli
2
+
3
+ raise SystemExit(cli())
git_omit/_version.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "0.0.1"
git_omit/_version.pyi ADDED
@@ -0,0 +1 @@
1
+ __version__: str
git_omit/cli.py ADDED
@@ -0,0 +1,188 @@
1
+ import argparse
2
+ import subprocess
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ from git_omit import __version__
7
+
8
+
9
+ class GitError(RuntimeError):
10
+ pass
11
+
12
+
13
+ def _git(*args: str) -> subprocess.CompletedProcess[str]:
14
+ return subprocess.run(
15
+ ["git", *args],
16
+ check=False,
17
+ stdout=subprocess.PIPE,
18
+ stderr=subprocess.PIPE,
19
+ text=True,
20
+ encoding="utf-8",
21
+ errors="surrogateescape",
22
+ )
23
+
24
+
25
+ def _git_stdout(*args: str) -> str:
26
+ result = _git(*args)
27
+ if result.returncode != 0:
28
+ message = result.stderr.strip() or "git command failed"
29
+ raise GitError(message)
30
+ return result.stdout.strip()
31
+
32
+
33
+ def _git_path(path: str) -> Path:
34
+ value = _git_stdout("rev-parse", "--git-path", path)
35
+ return Path(value).resolve()
36
+
37
+
38
+ def _exclude_path() -> Path:
39
+ return _git_path("info/exclude")
40
+
41
+
42
+ def _read_lines(path: Path) -> list[str]:
43
+ if not path.exists():
44
+ return []
45
+ return path.read_text(encoding="utf-8").splitlines()
46
+
47
+
48
+ def _write_lines(path: Path, lines: list[str]) -> None:
49
+ path.parent.mkdir(parents=True, exist_ok=True)
50
+ content = "\n".join(lines)
51
+ if content:
52
+ content += "\n"
53
+ path.write_text(content, encoding="utf-8")
54
+
55
+
56
+ def hidden_patterns() -> list[str]:
57
+ return [
58
+ line
59
+ for line in _read_lines(_exclude_path())
60
+ if line.strip() and not line.lstrip().startswith("#")
61
+ ]
62
+
63
+
64
+ def hide(patterns: list[str]) -> None:
65
+ path = _exclude_path()
66
+ lines = _read_lines(path)
67
+ existing = set(lines)
68
+ changed = False
69
+
70
+ for pattern in patterns:
71
+ value = pattern.strip()
72
+ if value and value not in existing:
73
+ lines.append(value)
74
+ existing.add(value)
75
+ changed = True
76
+
77
+ if changed:
78
+ _write_lines(path, lines)
79
+
80
+
81
+ def unhide(patterns: list[str]) -> None:
82
+ targets = {pattern.strip() for pattern in patterns if pattern.strip()}
83
+ if not targets:
84
+ return
85
+
86
+ path = _exclude_path()
87
+ lines = _read_lines(path)
88
+ next_lines = [line for line in lines if line not in targets]
89
+ if len(next_lines) != len(lines):
90
+ _write_lines(path, next_lines)
91
+
92
+
93
+ def freeze(paths: list[str]) -> None:
94
+ _run_update_index("--skip-worktree", paths)
95
+
96
+
97
+ def unfreeze(paths: list[str]) -> None:
98
+ _run_update_index("--no-skip-worktree", paths)
99
+
100
+
101
+ def _run_update_index(flag: str, paths: list[str]) -> None:
102
+ result = _git("update-index", flag, "--", *paths)
103
+ if result.returncode != 0:
104
+ message = result.stderr.strip() or "git update-index failed"
105
+ raise GitError(message)
106
+
107
+
108
+ def frozen_paths() -> list[str]:
109
+ result = _git("ls-files", "-v", "-z")
110
+ if result.returncode != 0:
111
+ message = result.stderr.strip() or "git ls-files failed"
112
+ raise GitError(message)
113
+
114
+ paths: list[str] = []
115
+ for record in result.stdout.split("\0"):
116
+ if record.startswith("S "):
117
+ paths.append(record[2:])
118
+ return paths
119
+
120
+
121
+ def list_items() -> None:
122
+ for pattern in hidden_patterns():
123
+ print(f"hide\t{pattern}")
124
+ for path in frozen_paths():
125
+ print(f"freeze\t{path}")
126
+
127
+
128
+ def build_parser() -> argparse.ArgumentParser:
129
+ parser = argparse.ArgumentParser(
130
+ prog="git-omit",
131
+ description="Keep local Git noise local.",
132
+ )
133
+ parser.add_argument(
134
+ "--version",
135
+ action="version",
136
+ version=f"%(prog)s {__version__}",
137
+ )
138
+ subparsers = parser.add_subparsers(dest="command", required=True)
139
+
140
+ hide_parser = subparsers.add_parser(
141
+ "hide", help="Add patterns to .git/info/exclude"
142
+ )
143
+ hide_parser.add_argument("patterns", nargs="+")
144
+
145
+ unhide_parser = subparsers.add_parser(
146
+ "unhide", help="Remove patterns from .git/info/exclude"
147
+ )
148
+ unhide_parser.add_argument("patterns", nargs="+")
149
+
150
+ freeze_parser = subparsers.add_parser(
151
+ "freeze", help="Mark tracked files as skip-worktree"
152
+ )
153
+ freeze_parser.add_argument("paths", nargs="+")
154
+
155
+ unfreeze_parser = subparsers.add_parser(
156
+ "unfreeze", help="Clear skip-worktree from tracked files"
157
+ )
158
+ unfreeze_parser.add_argument("paths", nargs="+")
159
+
160
+ subparsers.add_parser("list", help="List hidden patterns and frozen paths")
161
+ return parser
162
+
163
+
164
+ def cli(argv: list[str] | None = None) -> int:
165
+ parser = build_parser()
166
+ args = parser.parse_args(argv)
167
+
168
+ try:
169
+ match args.command:
170
+ case "hide":
171
+ hide(args.patterns)
172
+ case "unhide":
173
+ unhide(args.patterns)
174
+ case "freeze":
175
+ freeze(args.paths)
176
+ case "unfreeze":
177
+ unfreeze(args.paths)
178
+ case "list":
179
+ list_items()
180
+ except GitError as exc:
181
+ print(f"git-omit: {exc}", file=sys.stderr)
182
+ return 1
183
+
184
+ return 0
185
+
186
+
187
+ if __name__ == "__main__":
188
+ raise SystemExit(cli())
@@ -0,0 +1,46 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-omit
3
+ Version: 0.0.1
4
+ Summary: Small Git helpers for local-only ignores and tracked files you want Git to leave alone
5
+ Author-email: Noai-oss <jiuwoxiao@outlook.com>
6
+ Requires-Python: >=3.14
7
+ Description-Content-Type: text/markdown
8
+
9
+ # git-omit
10
+
11
+ Small Git helpers for local-only ignores and tracked files you want Git to leave alone.
12
+
13
+ ## Local ignores
14
+
15
+ | Kind | Git mechanism | Use when |
16
+ | --- | --- | --- |
17
+ | Untracked | `.git/info/exclude` | The file should stay local and untracked |
18
+ | Tracked | `skip-worktree` | The file is tracked, but local changes should be left alone |
19
+
20
+ ## Installation
21
+
22
+ ```sh
23
+ uv tool install git-omit
24
+ # or from GitHub
25
+ uv tool install git+https://github.com/Noai-oss/git-omit
26
+ ```
27
+
28
+ ## Commands
29
+
30
+ | Command | Example | Effect |
31
+ | --- | --- | --- |
32
+ | `git-omit hide <pattern>...` | `git-omit hide '*.log'` | Add patterns to `.git/info/exclude` |
33
+ | `git-omit unhide <pattern>...` | `git-omit unhide '*.log'` | Remove patterns from `.git/info/exclude` |
34
+ | `git-omit freeze <path>...` | `git-omit freeze config.local.json` | Mark tracked files as `skip-worktree` |
35
+ | `git-omit unfreeze <path>...` | `git-omit unfreeze config.local.json` | Clear `skip-worktree` |
36
+ | `git-omit list` | `git-omit list` | Print hidden patterns and frozen paths |
37
+ | `git-omit --version` | `git-omit --version` | Print the version |
38
+
39
+ We recommend quoting glob patterns, like `'*.log'`, so your shell passes them unchanged.
40
+
41
+ `git-omit list` prints tab-separated lines:
42
+
43
+ ```text
44
+ hide *.log
45
+ freeze config.local.json
46
+ ```
@@ -0,0 +1,9 @@
1
+ git_omit/__init__.py,sha256=0VRY0I6G4MGwHEY4kTlK2iqXyv2PB7ueHrYt6WMm74k,116
2
+ git_omit/__main__.py,sha256=TOJrcKFbI6FZfkCu5urVrBqu8GnpP45SUDpJFE4cCDE,46
3
+ git_omit/_version.py,sha256=ry5O5SW74ugwOUMKSV2_LbWjYa8B0IEvUm7S-lHPA2c,23
4
+ git_omit/_version.pyi,sha256=Y25n44pyE3vp92MiABKrcK3IWRyQ1JG1rZ4Ufqy2nC0,17
5
+ git_omit/cli.py,sha256=6EyaJyyrXpu8WLW6KXm8AGxkHMSGQxFji6bNRaBhMG4,4844
6
+ git_omit-0.0.1.dist-info/METADATA,sha256=daWGXhX2vlJ3IxhXLTQ6J_XWZBBoKwQCIKGKUFTqhaw,1544
7
+ git_omit-0.0.1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
8
+ git_omit-0.0.1.dist-info/entry_points.txt,sha256=RmtMe53O3dY7j0Uq2sJi-PcuJlvJSlULm2mYn5w5Zuw,46
9
+ git_omit-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-omit = git_omit.cli:cli