@codragraph/cli 1.6.4 → 2.0.0
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.
- package/README.md +34 -0
- package/dist/cli/analyze.d.ts +22 -0
- package/dist/cli/analyze.js +107 -4
- package/dist/cli/compress-stats.d.ts +29 -0
- package/dist/cli/compress-stats.js +97 -0
- package/dist/cli/graphstore.d.ts +6 -2
- package/dist/cli/graphstore.js +24 -2
- package/dist/cli/index.js +16 -2
- package/dist/cli/profile-heap.d.ts +35 -0
- package/dist/cli/profile-heap.js +126 -0
- package/dist/cli/setup.d.ts +13 -0
- package/dist/cli/setup.js +22 -11
- package/dist/cli/skill-gen.d.ts +14 -2
- package/dist/cli/skill-gen.js +52 -19
- package/dist/cli/tool.js +4 -0
- package/dist/core/embeddings/embedding-pipeline.js +24 -7
- package/dist/core/group/bridge-db.js +111 -24
- package/dist/core/lbug/content-read.d.ts +46 -0
- package/dist/core/lbug/content-read.js +64 -0
- package/dist/core/lbug/csv-generator.d.ts +2 -6
- package/dist/core/lbug/csv-generator.js +45 -12
- package/dist/core/lbug/lbug-adapter.d.ts +4 -1
- package/dist/core/lbug/lbug-adapter.js +153 -21
- package/dist/core/lbug/schema.d.ts +7 -7
- package/dist/core/lbug/schema.js +18 -0
- package/dist/core/run-analyze.d.ts +13 -0
- package/dist/core/run-analyze.js +91 -4
- package/dist/core/search/bm25-index.js +67 -15
- package/dist/mcp/local/local-backend.js +22 -5
- package/dist/server/api.js +4 -3
- package/dist/storage/repo-manager.d.ts +39 -0
- package/dist/storage/repo-manager.js +19 -0
- package/hooks/claude/codragraph-hook.cjs +95 -2
- package/package.json +4 -4
- package/scripts/build-tree-sitter-proto.cjs +15 -3
- package/scripts/patch-tree-sitter-swift.cjs +17 -4
- package/skills/codragraph-api-surface.md +110 -0
- package/skills/codragraph-config-audit.md +146 -0
- package/skills/codragraph-cross-repo-impact.md +135 -0
- package/skills/codragraph-data-lineage.md +137 -0
- package/skills/codragraph-dead-code.md +119 -0
- package/skills/codragraph-gh-actions-debug.md +162 -0
- package/skills/codragraph-gh-issue-workflow.md +178 -0
- package/skills/codragraph-gh-pr-workflow.md +176 -0
- package/skills/codragraph-gh-release-workflow.md +187 -0
- package/skills/codragraph-git-bisect.md +176 -0
- package/skills/codragraph-git-force-push.md +147 -0
- package/skills/codragraph-git-history-rewrite.md +174 -0
- package/skills/codragraph-git-rebase-vs-merge.md +138 -0
- package/skills/codragraph-git-recovery.md +181 -0
- package/skills/codragraph-git-worktree.md +145 -0
- package/skills/codragraph-migration-tracking.md +130 -0
- package/skills/codragraph-notebook-context.md +136 -0
- package/skills/codragraph-observability-coverage.md +125 -0
- package/skills/codragraph-onboarding.md +129 -0
- package/skills/codragraph-perf-hotspots.md +132 -0
- package/skills/codragraph-project-switcher.md +116 -0
- package/skills/codragraph-security-audit.md +144 -0
- package/skills/codragraph-sql-tracing.md +122 -0
- package/skills/codragraph-supply-chain-audit.md +153 -0
- package/skills/codragraph-test-coverage.md +97 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codragraph-git-bisect
|
|
3
|
+
description: "Use when hunting a regression — narrowing down which commit introduced a bug across N commits using binary search. Covers manual bisect, automated bisect with a test script, and how to combine bisect with CodraGraph context to understand the bad commit. Examples: \"find which commit broke X\", \"git bisect\", \"regression hunt\", \"automated bisect\""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Regression Hunting with `git bisect`
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- "Tests pass at commit A but fail at commit B — which commit broke it?"
|
|
11
|
+
- "Performance regressed somewhere in the last 200 commits."
|
|
12
|
+
- "Find the commit that introduced this bug."
|
|
13
|
+
- "Automate a bisect with my test suite."
|
|
14
|
+
|
|
15
|
+
## The principle
|
|
16
|
+
|
|
17
|
+
Bisect performs binary search over the commit graph. Given a
|
|
18
|
+
known-good commit (`good`) and a known-bad commit (`bad`), it picks the
|
|
19
|
+
midpoint, you mark it, and it halves the search space until exactly one
|
|
20
|
+
commit is identified. Log₂(N) tests instead of N.
|
|
21
|
+
|
|
22
|
+
## Manual workflow
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Start
|
|
26
|
+
git bisect start
|
|
27
|
+
git bisect bad <known-bad> # often HEAD or a commit/tag
|
|
28
|
+
git bisect good <known-good> # something older that worked
|
|
29
|
+
|
|
30
|
+
# Now git checks out the midpoint. Test it.
|
|
31
|
+
# Mark each midpoint:
|
|
32
|
+
git bisect bad # if the bug IS present
|
|
33
|
+
git bisect good # if the bug is NOT present
|
|
34
|
+
git bisect skip # if the commit can't be tested
|
|
35
|
+
# (won't compile, broken in some other way)
|
|
36
|
+
|
|
37
|
+
# Bisect narrows down. Repeat marking until git announces:
|
|
38
|
+
# → "<sha> is the first bad commit"
|
|
39
|
+
|
|
40
|
+
# Done — back to your starting state:
|
|
41
|
+
git bisect reset
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Automated workflow
|
|
45
|
+
|
|
46
|
+
If you have a script that exits 0 on good and non-zero on bad, you can
|
|
47
|
+
fully automate:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
git bisect start HEAD <known-good>
|
|
51
|
+
git bisect run ./scripts/repro-bug.sh
|
|
52
|
+
# → bisect runs the script at each midpoint; marks good/bad automatically;
|
|
53
|
+
# announces the first bad commit when done
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The script's exit codes:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
exit 0 → mark as good
|
|
60
|
+
exit 1..124, → mark as bad
|
|
61
|
+
126..127
|
|
62
|
+
exit 125 → mark as skip (can't test this commit)
|
|
63
|
+
exit 128+ → abort the bisect
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Test-script template
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
#!/usr/bin/env bash
|
|
70
|
+
# scripts/repro-bug.sh — bisect-aware reproduction script
|
|
71
|
+
set -e
|
|
72
|
+
|
|
73
|
+
# 1. If this commit can't even build, skip it (don't say bad).
|
|
74
|
+
npm install --silent --no-audit > /dev/null 2>&1 || exit 125
|
|
75
|
+
npm run build > /dev/null 2>&1 || exit 125
|
|
76
|
+
|
|
77
|
+
# 2. Run the targeted test that demonstrates the bug.
|
|
78
|
+
if npx vitest run path/to/regression.test.ts --reporter=basic > /dev/null 2>&1; then
|
|
79
|
+
exit 0 # good
|
|
80
|
+
else
|
|
81
|
+
exit 1 # bad
|
|
82
|
+
fi
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Why CodraGraph helps here
|
|
86
|
+
|
|
87
|
+
Once bisect names the first bad commit, the next question is *why*
|
|
88
|
+
that commit broke things. CodraGraph's `diff --semantic` and `context`
|
|
89
|
+
tell you exactly what changed, structurally:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
git bisect log # see the bisection that found it
|
|
93
|
+
BAD=$(git bisect log | grep "first bad commit" | awk '{print $1}')
|
|
94
|
+
|
|
95
|
+
# What changed structurally between good and bad?
|
|
96
|
+
codragraph diff "$BAD"^ "$BAD" --semantic
|
|
97
|
+
# → addedAPIs / removedAPIs / classifiedModifications
|
|
98
|
+
|
|
99
|
+
# Get full context on the modified symbols
|
|
100
|
+
codragraph_context({name: "<symbol from the diff>"})
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
This turns "commit X is bad" into "commit X removed/modified Y, which
|
|
104
|
+
broke flow Z." That's the actionable answer.
|
|
105
|
+
|
|
106
|
+
## Bisect across non-linear history
|
|
107
|
+
|
|
108
|
+
If your history has merges, bisect handles them but the midpoints are
|
|
109
|
+
weird (commits from sibling branches). Two helpful flags:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
git bisect start --first-parent HEAD <known-good>
|
|
113
|
+
# → only follows the first-parent path (main line of merges).
|
|
114
|
+
# Useful when feature-branch commits aren't worth testing individually.
|
|
115
|
+
|
|
116
|
+
git bisect start --no-checkout HEAD <known-good>
|
|
117
|
+
# → don't checkout each midpoint; instead just sets BISECT_HEAD ref.
|
|
118
|
+
# Use when checkout is expensive (huge repo, slow build).
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Pitfalls
|
|
122
|
+
|
|
123
|
+
| Pitfall | What happens | Fix |
|
|
124
|
+
|---|---|---|
|
|
125
|
+
| Forgot to `bisect reset` after finishing | Stuck in detached state, future `git pull` weird | `git bisect reset` returns you to your branch |
|
|
126
|
+
| Test depends on uncommitted state | Bisect finds noise, not the real bug | Stash before bisecting; ensure script is self-contained |
|
|
127
|
+
| Build broken in middle of range | Every middle commit looks "bad" | Use `git bisect skip` or exit-code 125 in the auto script |
|
|
128
|
+
| Submodules not in sync | Wrong code being tested | Add `git submodule update --init --recursive` to the script |
|
|
129
|
+
| Found a "bad commit" that's a merge | Probably a transient issue or skip-worthy | Inspect the merge: `git show --first-parent <merge>` |
|
|
130
|
+
|
|
131
|
+
## Checklist
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
- [ ] Identified a clear known-good and known-bad commit
|
|
135
|
+
- [ ] Have a deterministic, single-command reproduction
|
|
136
|
+
- [ ] Repro is fast enough (<2 min ideally; bisect runs ~log₂(N) times)
|
|
137
|
+
- [ ] Build can complete on every commit in the range (or skip script handles it)
|
|
138
|
+
- [ ] Use `git bisect run <script>` for full automation
|
|
139
|
+
- [ ] After hit: codragraph diff <bad>^ <bad> --semantic to understand WHY
|
|
140
|
+
- [ ] git bisect reset before resuming work
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Example: "Tests started failing in the last 3 weeks"
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
# 1. Confirm endpoints
|
|
147
|
+
git checkout main && npx vitest run path/to/regression.test.ts
|
|
148
|
+
# → fails
|
|
149
|
+
|
|
150
|
+
git checkout v1.5.3 # known-good 3 weeks ago
|
|
151
|
+
npx vitest run path/to/regression.test.ts
|
|
152
|
+
# → passes
|
|
153
|
+
|
|
154
|
+
# 2. Automate
|
|
155
|
+
git bisect start main v1.5.3
|
|
156
|
+
cat > /tmp/repro.sh <<'EOF'
|
|
157
|
+
#!/usr/bin/env bash
|
|
158
|
+
set -e
|
|
159
|
+
npm install --silent || exit 125
|
|
160
|
+
npx vitest run path/to/regression.test.ts --reporter=basic > /dev/null 2>&1
|
|
161
|
+
EOF
|
|
162
|
+
chmod +x /tmp/repro.sh
|
|
163
|
+
git bisect run /tmp/repro.sh
|
|
164
|
+
# → "abc1234 is the first bad commit"
|
|
165
|
+
|
|
166
|
+
# 3. Understand the bad commit
|
|
167
|
+
codragraph diff abc1234^ abc1234 --semantic
|
|
168
|
+
# → modified validateUser (parameter count 3→4)
|
|
169
|
+
|
|
170
|
+
codragraph_context({name: "validateUser"})
|
|
171
|
+
# → caller `loginFlow` still passes 3 args — that's the regression
|
|
172
|
+
|
|
173
|
+
# 4. Reset and fix
|
|
174
|
+
git bisect reset
|
|
175
|
+
# Patch the caller; tests pass; ship.
|
|
176
|
+
```
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codragraph-git-force-push
|
|
3
|
+
description: "Use when the user is about to force-push, recovering after someone else force-pushed, or asking whether it's safe. Covers --force vs --force-with-lease, recovery from a bad force-push, and the rules for shared vs personal branches. Examples: \"force push\", \"is force push safe\", \"someone overwrote my work\", \"git push rejected\", \"--force-with-lease\""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Force Push — When, How, and Recovery
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- "Can I force push to this branch?"
|
|
11
|
+
- "Git is rejecting my push, is force the answer?"
|
|
12
|
+
- "Someone force-pushed and lost my commits — help."
|
|
13
|
+
- "What's the difference between --force and --force-with-lease?"
|
|
14
|
+
|
|
15
|
+
## The rules
|
|
16
|
+
|
|
17
|
+
1. **Never `--force` on a shared branch** without coordinating. You will
|
|
18
|
+
silently overwrite collaborators' commits. Their reflogs save them; their
|
|
19
|
+
patience does not.
|
|
20
|
+
2. **Always prefer `--force-with-lease`** over `--force`. It refuses the
|
|
21
|
+
push if the remote has commits you haven't seen — i.e. someone pushed
|
|
22
|
+
while you were rebasing.
|
|
23
|
+
3. **Never force on `main` / `master` / `release/*`** unless you're recovering
|
|
24
|
+
from a documented incident with explicit sign-off. Branch protection
|
|
25
|
+
should make this impossible; if it's possible, fix the protection rule.
|
|
26
|
+
4. **Force-pushing your OWN feature branch** after a rebase is normal and
|
|
27
|
+
expected. Just use `--force-with-lease`.
|
|
28
|
+
|
|
29
|
+
## Decision tree
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
Is the branch protected on the remote?
|
|
33
|
+
├─ yes → STOP. Don't force. Open a PR or get an admin to lift protection
|
|
34
|
+
│ for a documented operation.
|
|
35
|
+
└─ no → Is anyone else committing to this branch?
|
|
36
|
+
├─ yes → STOP. Coordinate. They'll lose work if you force.
|
|
37
|
+
└─ no → Have you fetched the latest remote tip?
|
|
38
|
+
├─ no → git fetch first, then `git push --force-with-lease`
|
|
39
|
+
└─ yes → `git push --force-with-lease` is safe.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## --force vs --force-with-lease
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
# DANGEROUS: overwrites whatever is on the remote, no matter what.
|
|
46
|
+
git push --force
|
|
47
|
+
|
|
48
|
+
# SAFER: only succeeds if the remote tip matches what you last fetched.
|
|
49
|
+
# If anyone pushed in the meantime, this aborts.
|
|
50
|
+
git push --force-with-lease
|
|
51
|
+
|
|
52
|
+
# EVEN SAFER: explicitly require the remote SHA to be what you expect.
|
|
53
|
+
git push --force-with-lease=<branch>:<expected-sha>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
> Make `--force-with-lease` your default by aliasing:
|
|
57
|
+
> `git config --global alias.fwl 'push --force-with-lease'`
|
|
58
|
+
|
|
59
|
+
## Recovery: someone force-pushed and lost your work
|
|
60
|
+
|
|
61
|
+
Your local clone has the original commits in its reflog. You haven't lost
|
|
62
|
+
anything as long as you haven't run `git gc --prune=now` AND your reflog
|
|
63
|
+
is still intact (default 90-day expiry).
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 1. Find the lost commit on YOUR machine
|
|
67
|
+
git reflog show <branch>
|
|
68
|
+
# → look for "<branch>@{N}: ... before force push" or your last commit
|
|
69
|
+
|
|
70
|
+
# 2. Inspect it
|
|
71
|
+
git show <sha>
|
|
72
|
+
git log <sha> --oneline -20
|
|
73
|
+
|
|
74
|
+
# 3a. If they overwrote with rubbish: reset your branch to your old tip
|
|
75
|
+
# (this re-creates the divergence; coordinate before re-pushing)
|
|
76
|
+
git checkout <branch>
|
|
77
|
+
git reset --hard <sha-from-reflog>
|
|
78
|
+
|
|
79
|
+
# 3b. If they had legitimate changes you also want to keep: cherry-pick
|
|
80
|
+
# YOUR lost commits onto their version
|
|
81
|
+
git checkout <branch>
|
|
82
|
+
git pull # accept their version
|
|
83
|
+
git cherry-pick <your-lost-sha-1> <your-lost-sha-2> ...
|
|
84
|
+
|
|
85
|
+
# 4. Push back (with --force-with-lease to avoid the same problem)
|
|
86
|
+
git push --force-with-lease
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
If the only copy of the lost commits was on the remote (no local clone),
|
|
90
|
+
the recovery options are:
|
|
91
|
+
|
|
92
|
+
- GitHub: contact GitHub Support — they retain dangling commits for ~30 days.
|
|
93
|
+
- Self-hosted GitLab/Gitea: server-side reflog (if enabled) or a backup.
|
|
94
|
+
|
|
95
|
+
## Recovery: I force-pushed something I shouldn't have
|
|
96
|
+
|
|
97
|
+
If you JUST did it and have a terminal where the previous local state still
|
|
98
|
+
exists:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
git reflog # find the previous tip
|
|
102
|
+
git reset --hard <previous-sha>
|
|
103
|
+
git push --force-with-lease # restore the remote
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If you've already moved on locally:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git fetch origin
|
|
110
|
+
git reflog show origin/<branch>
|
|
111
|
+
# → look for the line BEFORE the force push you just did
|
|
112
|
+
git reset --hard <recovered-sha>
|
|
113
|
+
git push --force-with-lease
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Why CodraGraph helps here
|
|
117
|
+
|
|
118
|
+
After a force-push (yours or theirs), `codragraph diff` against the
|
|
119
|
+
recovered SHA tells you EXACTLY what structural changes were undone or
|
|
120
|
+
reapplied — so you can verify nothing important got lost in the
|
|
121
|
+
recovery:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
codragraph diff <recovered-sha> HEAD --semantic
|
|
125
|
+
# If addedAPIs / removedAPIs reveals work that should still be present,
|
|
126
|
+
# the recovery is incomplete — go back to the reflog and pick more.
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Checklist (before any --force / --force-with-lease)
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
- [ ] Branch is NOT protected on the remote
|
|
133
|
+
- [ ] Branch is NOT main / master / release/*
|
|
134
|
+
- [ ] You're the only one committing to it (git log <branch> | grep -c Author)
|
|
135
|
+
- [ ] You've git-fetched recently (so --force-with-lease has fresh info)
|
|
136
|
+
- [ ] Using --force-with-lease, NEVER bare --force
|
|
137
|
+
- [ ] If recovering: verified the recovered SHA via codragraph diff
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Pitfalls
|
|
141
|
+
|
|
142
|
+
| Pitfall | What goes wrong | Avoidance |
|
|
143
|
+
|---|---|---|
|
|
144
|
+
| `git push -f` on shared branch | collaborators' commits silently gone | --force-with-lease + check `git log <branch>` for other authors first |
|
|
145
|
+
| `--force-with-lease` after `git fetch` | lease check passes against the freshly-fetched tip — no protection | run lease BEFORE the fetch, or specify the expected SHA explicitly |
|
|
146
|
+
| Force-push during CI run | CI race conditions, half-deployed states | wait for CI to finish, then force |
|
|
147
|
+
| Forgetting reflog can save you | panic | reflogs default to 90 days; check `git reflog` before destroying anything |
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codragraph-git-history-rewrite
|
|
3
|
+
description: "Use when rewriting commit history — squashing WIP commits, splitting a fat commit, removing a leaked secret, changing author info, or running git filter-repo / BFG. Covers interactive rebase, fixup/autosquash, splitting commits, and the safety rules for rewriting public history. Examples: \"squash my commits\", \"clean up history\", \"remove a leaked secret from history\", \"split this commit\", \"git filter-repo\""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# History Rewriting — Safely
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- "Squash my last 5 WIP commits before opening a PR."
|
|
11
|
+
- "Split this giant commit into 3 logical ones."
|
|
12
|
+
- "Remove a leaked secret from history."
|
|
13
|
+
- "Change the author of past commits."
|
|
14
|
+
- "Drop a commit from the middle of the branch."
|
|
15
|
+
|
|
16
|
+
## The cardinal rule
|
|
17
|
+
|
|
18
|
+
**Never rewrite history that's been pushed to a shared branch.** Rewriting
|
|
19
|
+
public history breaks every clone that pulled it. For shared branches:
|
|
20
|
+
make a new commit that fixes/reverts the offending one. For your own
|
|
21
|
+
branch (or any branch you alone work on), rewrite freely with
|
|
22
|
+
`--force-with-lease`.
|
|
23
|
+
|
|
24
|
+
## Interactive rebase
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
git rebase -i origin/main # rebase your branch onto main, interactively
|
|
28
|
+
# OR rebase the last N commits without changing the base:
|
|
29
|
+
git rebase -i HEAD~N
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
You get an editor with one line per commit:
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
pick abc1234 wip: hack on auth
|
|
36
|
+
pick def5678 wip: more auth
|
|
37
|
+
pick fed9876 fix typo
|
|
38
|
+
pick 012abcd add real auth flow
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Change `pick` to one of:
|
|
42
|
+
|
|
43
|
+
| Command | Effect |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `pick` | keep the commit as-is |
|
|
46
|
+
| `reword` | keep the changes, edit the message |
|
|
47
|
+
| `edit` | pause after applying so you can `git commit --amend` or split |
|
|
48
|
+
| `squash` | merge into previous commit, edit combined message |
|
|
49
|
+
| `fixup` | merge into previous commit, drop this commit's message |
|
|
50
|
+
| `drop` | remove the commit entirely (its changes are gone) |
|
|
51
|
+
| `exec <cmd>` | run a shell command after this commit (CI-style validation per commit) |
|
|
52
|
+
|
|
53
|
+
Reorder lines to reorder commits. Save and exit; rebase replays them.
|
|
54
|
+
|
|
55
|
+
## Fixup + autosquash workflow (the cleanest pattern)
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# While developing, instead of "wip" commits, mark fixups against a target:
|
|
59
|
+
git commit --fixup=<sha-of-target-commit>
|
|
60
|
+
|
|
61
|
+
# At the end, squash all fixups in one go:
|
|
62
|
+
git rebase -i --autosquash origin/main
|
|
63
|
+
# → all `fixup!` commits are auto-placed and pre-marked. Just save.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This produces a clean, atomic-commit branch ready to PR — no manual
|
|
67
|
+
reordering needed.
|
|
68
|
+
|
|
69
|
+
## Splitting a fat commit
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git rebase -i <commit>^ # interactive rebase starting AT the fat commit
|
|
73
|
+
# Mark it `edit` and save.
|
|
74
|
+
|
|
75
|
+
# Now you're paused at the fat commit. Reset to its parent, keep the changes:
|
|
76
|
+
git reset HEAD^
|
|
77
|
+
|
|
78
|
+
# Stage and commit each logical chunk separately:
|
|
79
|
+
git add <files-for-part-1>
|
|
80
|
+
git commit -m "first logical part"
|
|
81
|
+
git add <files-for-part-2>
|
|
82
|
+
git commit -m "second logical part"
|
|
83
|
+
git add -A
|
|
84
|
+
git commit -m "third logical part"
|
|
85
|
+
|
|
86
|
+
# Resume the rebase:
|
|
87
|
+
git rebase --continue
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Removing a leaked secret from history
|
|
91
|
+
|
|
92
|
+
If a secret (API key, password, .env) was committed:
|
|
93
|
+
|
|
94
|
+
1. **Rotate the secret first.** Once it's on a public remote, treat it as
|
|
95
|
+
leaked — even after history scrub.
|
|
96
|
+
2. **Then scrub history with `git filter-repo`** (the modern replacement
|
|
97
|
+
for `filter-branch`):
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Install: pip install git-filter-repo (or pipx)
|
|
101
|
+
|
|
102
|
+
# Remove a specific file from all history:
|
|
103
|
+
git filter-repo --invert-paths --path path/to/leaked.env
|
|
104
|
+
|
|
105
|
+
# Or remove a string/secret from blob contents:
|
|
106
|
+
echo 'sk_live_abc***123==>REDACTED' > /tmp/replacements.txt
|
|
107
|
+
git filter-repo --replace-text /tmp/replacements.txt
|
|
108
|
+
|
|
109
|
+
# After filter-repo, the remote is forcibly out of sync. Coordinate with the
|
|
110
|
+
# team and force-push:
|
|
111
|
+
git push --force-with-lease origin --all
|
|
112
|
+
git push --force-with-lease origin --tags
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Alternative: BFG (`https://rtyley.github.io/bfg-repo-cleaner/`) is
|
|
116
|
+
faster for large repos but more limited.
|
|
117
|
+
|
|
118
|
+
> **Important:** GitHub caches blobs even after force-push. The blob is
|
|
119
|
+
> still accessible by SHA URL for ~30 days unless you contact GitHub
|
|
120
|
+
> Support to purge. Treat the secret as compromised.
|
|
121
|
+
|
|
122
|
+
## Changing author info on past commits
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Most recent commit only:
|
|
126
|
+
git commit --amend --author="New Name <new@email>"
|
|
127
|
+
|
|
128
|
+
# Multiple commits with filter-repo:
|
|
129
|
+
git filter-repo --commit-callback '
|
|
130
|
+
if commit.author_email == b"old@email":
|
|
131
|
+
commit.author_email = b"new@email"
|
|
132
|
+
commit.author_name = b"New Name"
|
|
133
|
+
'
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Why CodraGraph helps here
|
|
137
|
+
|
|
138
|
+
After any history rewrite, the structural diff against the pre-rewrite
|
|
139
|
+
state proves you didn't accidentally drop or alter functional code:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Before rewrite: snapshot the structural state
|
|
143
|
+
codragraph commit -m "pre-rewrite snapshot"
|
|
144
|
+
git rebase -i origin/main # do the rewrite
|
|
145
|
+
codragraph analyze # re-index after
|
|
146
|
+
|
|
147
|
+
# Confirm structural equivalence (or see exactly what differs):
|
|
148
|
+
codragraph diff <pre-snapshot-id> HEAD --semantic
|
|
149
|
+
# → Should be empty if you only rewrote messages / order.
|
|
150
|
+
# → If addedAPIs / removedAPIs appear, the rewrite changed semantics.
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## Pitfalls
|
|
154
|
+
|
|
155
|
+
| Pitfall | What goes wrong | Avoidance |
|
|
156
|
+
|---|---|---|
|
|
157
|
+
| Rewriting shared branch | Collaborators' clones diverge | Only rewrite local-or-personal branches |
|
|
158
|
+
| `drop` instead of `fixup` | Lost changes silently | Verify with `codragraph diff` after the rebase |
|
|
159
|
+
| Editing during rebase, forgetting `--continue` | Stuck in detached state | `git rebase --continue` after each manual step |
|
|
160
|
+
| `git rebase --abort` after edits | Loses your edits | Stash before rebase if you have uncommitted work |
|
|
161
|
+
| `filter-branch` (legacy) | Slow, error-prone, deprecated | Use `git filter-repo` |
|
|
162
|
+
| Force-pushing after secret scrub without rotation | Secret still compromised | Rotate FIRST, scrub SECOND |
|
|
163
|
+
|
|
164
|
+
## Checklist before any history rewrite
|
|
165
|
+
|
|
166
|
+
```
|
|
167
|
+
- [ ] Branch is NOT shared (or you have explicit team coordination)
|
|
168
|
+
- [ ] Snapshot pre-state with `codragraph commit -m "pre-rewrite"`
|
|
169
|
+
- [ ] Decide: interactive rebase (small) vs filter-repo (large/secrets)
|
|
170
|
+
- [ ] Run the rewrite
|
|
171
|
+
- [ ] Re-analyze + `codragraph diff` to verify no semantic surprises
|
|
172
|
+
- [ ] Push with --force-with-lease
|
|
173
|
+
- [ ] If secrets were involved: rotate FIRST, then scrub, then push
|
|
174
|
+
```
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: codragraph-git-rebase-vs-merge
|
|
3
|
+
description: "Use when deciding between rebase, merge, squash-merge, or rebase-and-merge for integrating a branch — both for local catch-up (pulling main into a feature branch) and for landing a PR. Examples: \"should I rebase or merge\", \"how do I integrate main into my branch\", \"squash vs rebase merge\", \"clean up my branch history before PR\""
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Rebase vs Merge — A Decision Guide
|
|
7
|
+
|
|
8
|
+
## When to Use
|
|
9
|
+
|
|
10
|
+
- "How do I bring main into my feature branch?"
|
|
11
|
+
- "Should I squash this PR or merge it?"
|
|
12
|
+
- "Should I rebase before pushing?"
|
|
13
|
+
- "Which merge strategy do I pick on the GitHub PR button?"
|
|
14
|
+
- Any time you have a branch and need to combine it with another.
|
|
15
|
+
|
|
16
|
+
## The decision rule (read this first)
|
|
17
|
+
|
|
18
|
+
| Situation | Use | Why |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| Branch is **local-only**, you want it to track main | `git pull --rebase` or `git rebase main` | Keeps your local history linear; nothing has been shared yet |
|
|
21
|
+
| Branch is **shared** (already pushed, others may have pulled) | `git merge main` (or `--no-rebase`) | Rebase rewrites SHAs — collaborators' clones break |
|
|
22
|
+
| You're about to **open a PR** and want clean history | `git rebase -i main` (interactive) | Squash WIP commits, reword messages, end with N tidy commits |
|
|
23
|
+
| You're **landing a PR** with one logical change | **Squash-merge** on GitHub | One commit on main, clean log, PR description becomes the body |
|
|
24
|
+
| You're landing a PR with multiple **already-tidy** commits | **Rebase-and-merge** on GitHub | Preserves your atomic commits; no merge bubble |
|
|
25
|
+
| You're landing a long-running branch that **must show as a unit** | **Merge commit** on GitHub | Preserves the branch topology — useful for release branches |
|
|
26
|
+
|
|
27
|
+
If you remember nothing else: **rebase what's only yours, merge what's already shared.**
|
|
28
|
+
|
|
29
|
+
## Workflow: catching up a feature branch
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Local-only branch (fast-forward integration)
|
|
33
|
+
git fetch origin
|
|
34
|
+
git rebase origin/main # replays your commits on top of main
|
|
35
|
+
|
|
36
|
+
# Already pushed branch (avoid SHA churn for collaborators)
|
|
37
|
+
git fetch origin
|
|
38
|
+
git merge origin/main # creates a merge commit — collaborators stay in sync
|
|
39
|
+
|
|
40
|
+
# OR explicitly opt into rebase even on shared branches (coordinate first!)
|
|
41
|
+
git rebase origin/main
|
|
42
|
+
git push --force-with-lease # SEE codragraph-git-force-push skill
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Workflow: cleaning up before opening a PR
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
git fetch origin
|
|
49
|
+
git rebase -i origin/main # interactive — squash, fixup, reword
|
|
50
|
+
|
|
51
|
+
# Common interactive-rebase actions:
|
|
52
|
+
# pick - keep commit
|
|
53
|
+
# reword - change message
|
|
54
|
+
# squash - merge into previous, edit combined message
|
|
55
|
+
# fixup - merge into previous, drop this message
|
|
56
|
+
# drop - remove the commit entirely
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Workflow: landing a PR (GitHub UI / `gh pr merge`)
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Squash-merge — one logical change, one commit on main:
|
|
63
|
+
gh pr merge --squash --delete-branch
|
|
64
|
+
|
|
65
|
+
# Rebase-and-merge — preserve your N commits as N commits on main:
|
|
66
|
+
gh pr merge --rebase --delete-branch
|
|
67
|
+
|
|
68
|
+
# Merge commit — preserve the branch as a unit (rare; use for releases):
|
|
69
|
+
gh pr merge --merge --delete-branch
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Why CodraGraph helps here
|
|
73
|
+
|
|
74
|
+
The hardest part of choosing a strategy isn't the mechanics — it's
|
|
75
|
+
predicting whether your branch will conflict structurally with main.
|
|
76
|
+
CodraGraph's `diff --semantic` tells you exactly which APIs / signatures
|
|
77
|
+
changed on each side, so you can see *before* the merge whether your
|
|
78
|
+
branch and main both touched the same callgraph regions.
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
codragraph diff main HEAD --semantic --json | jq '.semantic'
|
|
82
|
+
→ added APIs / removed APIs / classified modifications on YOUR branch
|
|
83
|
+
|
|
84
|
+
codragraph diff <last-shared-ancestor> main --semantic --json | jq '.semantic'
|
|
85
|
+
→ what main has done since you forked
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If both diffs touch overlapping symbols, prefer **merge** (preserves both
|
|
89
|
+
sides as branches you can reason about) over rebase (which re-writes your
|
|
90
|
+
side and may produce noisy conflicts).
|
|
91
|
+
|
|
92
|
+
## Pitfalls
|
|
93
|
+
|
|
94
|
+
| Pitfall | Symptom | Fix |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| Rebasing a shared branch | Collaborators report "diverged history", lost commits | Merge instead; don't rebase shared branches without coordination |
|
|
97
|
+
| Squash-merge into long-running branch | Loses individual commit context | Use rebase-and-merge for branches that need history preserved |
|
|
98
|
+
| `git pull` without `--rebase` flag on a feature branch | Random merge bubbles in your branch | Set `git config --global pull.rebase true` or always `pull --rebase` on feature branches |
|
|
99
|
+
| Rebasing ON TOP of work in progress (uncommitted) | "Your local changes would be overwritten" | `git stash` first, rebase, `git stash pop` |
|
|
100
|
+
|
|
101
|
+
## Checklist before merging a PR
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
- [ ] CI green (lint, tests, typecheck)
|
|
105
|
+
- [ ] codragraph_detect_changes({scope: "compare", base_ref: "main"}) clean
|
|
106
|
+
- [ ] codragraph diff main HEAD --semantic — review removed APIs
|
|
107
|
+
- [ ] PR description matches the (would-be-squash) commit message
|
|
108
|
+
- [ ] Decided strategy: squash (single change) vs rebase-and-merge (multiple atomic) vs merge (release/topology)
|
|
109
|
+
- [ ] gh pr merge --squash --delete-branch (or appropriate flag)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Example: "Should I rebase or merge main into my 4-day-old branch?"
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
1. Check if the branch is shared:
|
|
116
|
+
git config branch.<your-branch>.remote
|
|
117
|
+
→ "origin" — yes, pushed.
|
|
118
|
+
|
|
119
|
+
2. Check who else might have it:
|
|
120
|
+
gh api repos/{owner}/{repo}/pulls?head={your-branch} --jq '.[].user.login'
|
|
121
|
+
git log origin/<your-branch>..main --oneline | head
|
|
122
|
+
→ no co-authors observed; just you and CI.
|
|
123
|
+
|
|
124
|
+
3. Check structural conflict potential:
|
|
125
|
+
codragraph diff main <your-branch> --semantic
|
|
126
|
+
→ 2 added APIs, 1 modified signature
|
|
127
|
+
codragraph diff <merge-base> main --semantic
|
|
128
|
+
→ 0 changes touching the same files
|
|
129
|
+
→ no structural conflict expected.
|
|
130
|
+
|
|
131
|
+
4. Decision: rebase (it's effectively local) + force-with-lease.
|
|
132
|
+
git fetch origin
|
|
133
|
+
git rebase origin/main
|
|
134
|
+
# Resolve any conflicts file-by-file
|
|
135
|
+
git push --force-with-lease
|
|
136
|
+
|
|
137
|
+
5. If structural conflict HAD been likely → merge, not rebase.
|
|
138
|
+
```
|