git-trace 1.0.0__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_trace/utils.py ADDED
@@ -0,0 +1,84 @@
1
+ from __future__ import annotations
2
+ from enum import Enum
3
+
4
+
5
+ class Color(Enum):
6
+ RESET = "\033[0m"
7
+
8
+ BOLD = "\033[1m"
9
+ DIM = "\033[2m"
10
+ ITALIC = "\033[3m"
11
+ UNDERLINE = "\033[4m"
12
+ BLINK = "\033[5m"
13
+ REVERSE = "\033[7m"
14
+ HIDDEN = "\033[8m"
15
+
16
+ BLACK = "\033[30m"
17
+ RED = "\033[31m"
18
+ GREEN = "\033[32m"
19
+ YELLOW = "\033[33m"
20
+ BLUE = "\033[34m"
21
+ MAGENTA = "\033[35m"
22
+ CYAN = "\033[36m"
23
+ WHITE = "\033[37m"
24
+
25
+ BRIGHT_BLACK = "\033[90m"
26
+ BRIGHT_RED = "\033[91m"
27
+ BRIGHT_GREEN = "\033[92m"
28
+ BRIGHT_YELLOW = "\033[93m"
29
+ BRIGHT_BLUE = "\033[94m"
30
+ BRIGHT_MAGENTA = "\033[95m"
31
+ BRIGHT_CYAN = "\033[96m"
32
+ BRIGHT_WHITE = "\033[97m"
33
+
34
+ BG_BLACK = "\033[40m"
35
+ BG_RED = "\033[41m"
36
+ BG_GREEN = "\033[42m"
37
+ BG_YELLOW = "\033[43m"
38
+ BG_BLUE = "\033[44m"
39
+ BG_MAGENTA = "\033[45m"
40
+ BG_CYAN = "\033[46m"
41
+ BG_WHITE = "\033[47m"
42
+
43
+ BG_BRIGHT_BLACK = "\033[100m"
44
+ BG_BRIGHT_RED = "\033[101m"
45
+ BG_BRIGHT_GREEN = "\033[102m"
46
+ BG_BRIGHT_YELLOW = "\033[103m"
47
+ BG_BRIGHT_BLUE = "\033[104m"
48
+ BG_BRIGHT_MAGENTA = "\033[105m"
49
+ BG_BRIGHT_CYAN = "\033[106m"
50
+ BG_BRIGHT_WHITE = "\033[107m"
51
+
52
+
53
+ # TODO: make configurable ?
54
+ SHORT_HASH_LENGTH: int = 7
55
+
56
+ MAX_COMMIT_MESSAGE_LENGTH: int = 48
57
+
58
+ WARNING_COLOR: Color = Color.YELLOW
59
+ INFO_COLOR: Color = Color.BRIGHT_BLUE
60
+ ERROR_COLOR: Color = Color.BRIGHT_RED
61
+
62
+
63
+ def cprint(text: str, color: Color | None = None, end: str = "\n"):
64
+ if color is not None:
65
+ print(f"{color.value}{text}{Color.RESET.value}", end=end)
66
+ else:
67
+ print(text, end=end)
68
+
69
+
70
+ def yaml2list(value: object) -> list[str] | None:
71
+ if value is None:
72
+ return None
73
+ if isinstance(value, list):
74
+ return [str(item) for item in value]
75
+ return [str(value)]
76
+
77
+
78
+ def read_cleaned_file(path: str) -> list[str]:
79
+ with open(path, "r", encoding="utf-8") as file:
80
+ return [
81
+ stripped
82
+ for line in file
83
+ if (stripped := line.strip()) and not stripped.startswith("#")
84
+ ]
git_trace/version.py ADDED
@@ -0,0 +1,2 @@
1
+ __version__ = "1.0.0"
2
+ VERSION = __version__.split(".")
@@ -0,0 +1,221 @@
1
+ Metadata-Version: 2.4
2
+ Name: git-trace
3
+ Version: 1.0.0
4
+ Summary: Visualise git commit dependencies – see which commits edit lines introduced by earlier commits.
5
+ Author-email: Karol Kiszka <karolkisz22@gmail.com>
6
+ License: MIT
7
+ Project-URL: source, https://github.com/kiszkacy/git-trace
8
+ Keywords: git
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Development Status :: 4 - Beta
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Operating System :: OS Independent
18
+ Classifier: Environment :: Console
19
+ Requires-Python: <4.0,>=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: pyvis>=0.3
23
+ Requires-Dist: pyyaml>=6.0
24
+ Requires-Dist: colorama>=0.4.6
25
+ Dynamic: license-file
26
+
27
+ # git-trace
28
+
29
+ ![Python version](https://img.shields.io/badge/python-%3E%3D%203.10-blue.svg)
30
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
31
+ ![PyPI](https://img.shields.io/pypi/v/git-trace.svg)
32
+
33
+ Visualize commit dependencies in a git repository. For a given branch (or commit
34
+ range) `git-trace` analyses every diff and reports which commits **depend** on
35
+ earlier ones, in the sense that they modify or remove lines previously added by
36
+ those earlier commits. The result is rendered as either a text tree, a plain
37
+ list, or an interactive HTML graph.
38
+
39
+ > **Disclaimer:** This tool was built specifically with single-branch analysis in mind.
40
+ > While it **might** work across divergent branches, your mileage may vary and
41
+ > I am not responsible for any inaccurate results if you choose to use it that way.
42
+
43
+ A secondary mode (`--picks`) treats the analysis as a cherry-pick safety check:
44
+ given a set of commit hashes you intend to pick, it tells you which are safe,
45
+ which are blocked by missing dependencies, and which would become "conditional"
46
+ on picking other commits as well.
47
+
48
+ ![git-trace demo](docs/demo.png)
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install git-trace
54
+ ```
55
+
56
+ or from source:
57
+
58
+ ```bash
59
+ git clone https://github.com/kiszkacy/git-trace
60
+ cd git-trace
61
+ pip install -e .
62
+ ```
63
+
64
+ Requires Python 3.10+ and `git` available via `PATH`.
65
+
66
+ ## Quick start
67
+
68
+ Run from inside a git repository:
69
+
70
+ ```bash
71
+ git-trace # analyse the full history of 'main'
72
+ git-trace dev # analyse 'dev' branch
73
+ git-trace dev --after abc1234 # only commits after a hash
74
+ git-trace dev --after abc --before def # a commit range
75
+ git-trace --no-graph # skip HTML, print text only
76
+ git-trace --list # simplified list output + HTML graph
77
+ git-trace --list --no-graph # simplified list output only
78
+ ```
79
+
80
+ For cherry-pick analysis:
81
+
82
+ ```bash
83
+ git-trace dev --picks h1 h2 h3 # check whether picks are safe
84
+ git-trace dev --picks picks.txt # picks from a file
85
+ ```
86
+
87
+ By default `git-trace` writes an interactive HTML graph to `./output.html` and
88
+ also prints a text summary to stdout.
89
+
90
+ ## CLI arguments
91
+
92
+ | Argument | Description |
93
+ | --- | --- |
94
+ | `branch` | Branch to analyse. Defaults to `main`. Positional. |
95
+ | `--after HASH` | Only include commits *after* this hash (the hash itself is excluded). |
96
+ | `--before HASH` | Only include commits up to this hash (the hash itself is excluded). |
97
+ | `--whitelist HASH... \| FILE` | Restrict analysis to these hashes, or to a file containing hashes (one per line). Takes priority over `--blacklist`. Auto-loaded from `whitelist.txt` if present and the flag is omitted. |
98
+ | `--blacklist HASH... \| FILE` | Exclude these hashes from analysis, or a file containing hashes. Auto-loaded from `blacklist.txt` if present. |
99
+ | `--picks HASH... \| FILE` | Enable cherry-pick analysis. The given hashes are treated as the intended pick set; the tool reports safe / blocked / conditional picks. Auto-loaded from `picks.txt` if present. |
100
+ | `--ignore-paths PATH... \| FILE` | Repository-relative paths whose diffs should be ignored during analysis, or a file listing such paths. Auto-loaded from `ignore-paths.txt` if present. |
101
+ | `--repo DIR` | Path to the git repository root. Defaults to the current directory. |
102
+ | `--config FILE` | Path to a YAML config file. Defaults to `./config.yml`. |
103
+ | `--no-graph` | Skip HTML graph generation. |
104
+ | `--list` | Print a simple list of relevant commit hashes (one per line) instead of the formatted text tree. The HTML graph is still generated; combine with `--no-graph` to suppress it. |
105
+ | `--output PATH` | Path for the generated HTML graph. Defaults to `./output.html`. |
106
+ | `--txt-output PATH` | Also write the text output to this file. |
107
+ | `-v`, `--version` | Print version and exit. |
108
+
109
+ ### Precedence rules
110
+
111
+ 1. CLI arguments
112
+ 2. `config.yml` values (if the file exists)
113
+ 3. Auto-loaded files (`whitelist.txt`, `blacklist.txt`, `picks.txt`, `ignore-paths.txt`)
114
+
115
+ A more specific source overrides a less specific one
116
+ (i.e. CLI wins over config, config wins over auto-load).
117
+
118
+ ## config.yml
119
+
120
+ If a file named `config.yml` exists in the current working directory it is
121
+ loaded automatically. Pass `--config FILE` to use a different path. Any CLI
122
+ option can be set there. Example:
123
+
124
+ ```yaml
125
+ branch: dev
126
+ after: abc1234
127
+ ignore-paths:
128
+ - vendor/
129
+ - generated/
130
+ output: ./trace.html
131
+ no-graph: false
132
+ picks:
133
+ - a1b2c3d
134
+ - 9988776
135
+ ```
136
+
137
+ Keys mirror the CLI flag names (use `-` not `_`). Values may be strings, lists,
138
+ or booleans depending on the option.
139
+
140
+ ## Auto-loaded files
141
+
142
+ If you omit a flag, `git-trace` looks in the current directory for a matching
143
+ file and loads it automatically:
144
+
145
+ | File | Equivalent flag |
146
+ | --- | --- |
147
+ | `whitelist.txt` | `--whitelist` |
148
+ | `blacklist.txt` | `--blacklist` |
149
+ | `picks.txt` | `--picks` |
150
+ | `ignore-paths.txt` | `--ignore-paths` |
151
+
152
+ Each file holds one entry per line. Blank lines and lines starting with `#` are
153
+ ignored.
154
+
155
+ ## Output
156
+
157
+ - **Formatted text** (default): a tree-style listing of commits and their
158
+ dependencies, printed to stdout.
159
+ - **HTML graph** (default): an interactive force-directed graph written to
160
+ `./output.html`. Open it in any browser.
161
+ - **`--list`**: a flat list of hashes (one per line), suitable for piping into
162
+ other scripts. The HTML graph is still produced unless `--no-graph` is also specified.
163
+ - **`--txt-output FILE`**: also write the formatted text to a file.
164
+
165
+ In `--picks` mode the text output is grouped into `safe`, `blocked` (with the
166
+ list of missing dependencies for each) and `conditional` sections, while the HTML
167
+ graph highlights the pick set, blockers, and conditionals in distinct colors.
168
+
169
+ ## How dependency detection works
170
+
171
+ `git-trace` uses a position-aware analyzer. For each commit it replays the
172
+ diff hunks against a virtual snapshot of every file, tracked as a list of
173
+ `(line_content, owning_commit)` pairs. When a later commit removes or
174
+ overwrites a line, the analyzer consults the owner stored for that exact
175
+ position and records a dependency on whichever earlier commit introduced
176
+ that line. Identical line content appearing in different places of a file is
177
+ correctly treated as independent.
178
+
179
+ The analyzer handles file creation, deletion (`+++ /dev/null`), renames
180
+ (`rename from` / `rename to`), and the `@@ -X,0 +Y,N @@` insertion hunks
181
+ correctly.
182
+
183
+ ### Textual vs. Structural Dependencies
184
+
185
+ It is important to note that git-trace evaluates **purely textual dependencies**,
186
+ not structural or semantic ones. It only tracks modifications on a line-by-line basis.
187
+ It does not parse an Abstract Syntax Tree (AST) to understand code logic,
188
+ variable scopes, or function calls.
189
+
190
+ ## Known limitations
191
+
192
+ - **Copies (`copy from` / `copy to`)** → a copied file is treated as a fresh
193
+ new file rather than inheriting history from the source path. In practice
194
+ this is rare since git rarely produces copy markers by default.
195
+ - **Binary files** are silently skipped → no dependency is recorded for
196
+ changes to binary blobs.
197
+ - **Mode-only changes** (e.g. `chmod`) → are silently ignored, since they
198
+ don't affect any tracked content.
199
+ - **Quoted paths in diffs** (`core.quotePath`) → git's `core.quotePath`
200
+ setting (default: `true`) wraps file paths containing non-ASCII or special
201
+ characters in backslash-escaped double quotes when producing diff output.
202
+ The analyser reads paths literally after `+++ b/`, so a quoted path will
203
+ not match its real on-disk name. If you analyse a repo with non-ASCII
204
+ filenames, set `git config core.quotePath false` first.
205
+ - **`diff.noprefix` / `--no-prefix` diffs** → when `diff.noprefix` is
206
+ enabled, git's diff output omits the `a/` and `b/` path prefixes (e.g.
207
+ `--- file.txt` instead of `--- a/file.txt`). The analyser specifically
208
+ looks for the `a/` and `b/` prefixes to identify files, so under that
209
+ configuration no dependencies will be detected. Keep `diff.noprefix` at
210
+ its default (`false`) when running `git-trace`.
211
+
212
+ ## AI usage
213
+
214
+ LLM was used during the development of this project, specifically for:
215
+ - Writing the core dependency detection logic and processing the Git hunk headers.
216
+ - Injecting the custom HTML templates and dynamic styling payloads into pyvis html output.
217
+ - Generating most of the README.md content.
218
+
219
+ ## License
220
+
221
+ MIT &mdash; see [LICENSE](LICENSE).
@@ -0,0 +1,25 @@
1
+ git_trace/__init__.py,sha256=sLoG2b_UXsgAboKmqKAht0caM7wOb-t59LGE4xGmvzA,90
2
+ git_trace/__main__.py,sha256=hpG9V_OF_ZEiP7LEVsu5VwGxIv-pJq2ZhoE0uQ3C_5g,40
3
+ git_trace/analysis.py,sha256=ubCftMU_rAjKWx3Al-AbGSCRMN_lgjihXrWP7C0qT4A,7295
4
+ git_trace/git.py,sha256=DDxrRQ27_wveqlqoCuX_g5bgcX0qyIR8jmIROf65K8s,1985
5
+ git_trace/main.py,sha256=Zpbcu9rItNLXZSj-PRUBCWX8RjgDGZGYXoqODSqDhFQ,5591
6
+ git_trace/utils.py,sha256=LB3pKtc61UoasdqC0ZB0PmVru_HuPgYCC_vaTkDJvjY,2020
7
+ git_trace/version.py,sha256=oXo2yBb6TVZlnuNiWlGwrRYGRjUDgr2Lsdi7jeNsBlE,55
8
+ git_trace/input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
9
+ git_trace/input/args.py,sha256=VMEe92GFvivaMwqtdnQvYdm3WRT1wNYRDk3COK10G6Y,7108
10
+ git_trace/input/parser.py,sha256=04rB9fujKQU5ekjMvl4-ta25j8pS-orVW9nMrLMvxRM,6585
11
+ git_trace/output/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
12
+ git_trace/output/graph.py,sha256=8q5eznPqDpd2OA7yjPl5Ih7lkQuWq2E1VZ8aMOqMpvE,7918
13
+ git_trace/output/html_injection.py,sha256=WK_B5m6ByNm2xHTZK_GyAwSIsx43NVqR1itSUe7e3uE,924
14
+ git_trace/output/text.py,sha256=1WVnQuptRayvhHXU7VeLqdTtQLM7q_uRa2PJYv0yJc8,4172
15
+ git_trace/output/assets/analysis_controls.html,sha256=M7E6WMnYi8sRZm2jkZl0B5g7QQsu1-nlhFHnvB02BH4,3336
16
+ git_trace/output/assets/analysis_legend.html,sha256=De0N9I8-VaimMsz-Stu17BDmrfdoa8-QS3xPoyhmp9A,697
17
+ git_trace/output/assets/pick_controls.html,sha256=rD15mueaavMRj5A0M3SHgHCgCPOw8vvTM6gMMpkRbHA,4091
18
+ git_trace/output/assets/pick_legend.html,sha256=OvjcRXlJ_w7u5i392UcOdNBZw-b25w1d520LDJEoUpI,1081
19
+ git_trace/output/assets/styling.html,sha256=ZfUXAAdyJ8ZWT30eUYYkdqVJ97_Gz62XCktrQMXcrMk,89
20
+ git_trace-1.0.0.dist-info/licenses/LICENSE,sha256=PXKTIdUpzeVudoU3sRbr6Q7guZ-bEAtvGYZZEalvbvQ,1077
21
+ git_trace-1.0.0.dist-info/METADATA,sha256=hcxeHNGbtH2L5rGZuMtweU5RIXXEN435y3bmB5igrDs,9367
22
+ git_trace-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
23
+ git_trace-1.0.0.dist-info/entry_points.txt,sha256=ddqkSwgll-iCObso5z0YOM-K_JUfDyCiTCqbAh2e_dE,50
24
+ git_trace-1.0.0.dist-info/top_level.txt,sha256=9NrlAIs_e3v3UElq3U5y9UwstLEQ2dyDOd9jzafSVsM,10
25
+ git_trace-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ git-trace = git_trace.main:main
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026-present Karol Kiszka
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 @@
1
+ git_trace