@@ -172,6 +172,9 @@ def index(
172172 repo : Optional [str ] = typer .Option (
173173 None , "--repo" , help = "Graph name (defaults to folder name)"
174174 ),
175+ branch : Optional [str ] = typer .Option (
176+ None , "--branch" , help = "Branch to associate with this index (auto-detected from git checkout when omitted; '_default' for non-git paths)"
177+ ),
175178) -> None :
176179 """Index a local folder into the knowledge graph."""
177180 from .project import Project
@@ -204,14 +207,14 @@ def index(
204207
205208 _stderr (f"Indexing { folder } as '{ name } '…" )
206209 try :
207- project = Project (name , folder , url )
210+ project = Project (name , folder , url , branch = branch )
208211 graph = project .analyze_sources (ignore = list (ignore ) if ignore else [])
209212 stats = graph .stats ()
210213 except Exception as e :
211214 _json_error (str (e ))
212215
213- _stderr (f"Done — { stats ['node_count' ]} nodes, { stats ['edge_count' ]} edges" )
214- _json_out ({"status" : "ok" , "repo" : name , ** stats })
216+ _stderr (f"Done — { stats ['node_count' ]} nodes, { stats ['edge_count' ]} edges (branch= { project . branch } ) " )
217+ _json_out ({"status" : "ok" , "repo" : name , "branch" : project . branch , ** stats })
215218
216219
217220# ── index-repo ─────────────────────────────────────────────────────────
@@ -223,6 +226,9 @@ def index_repo(
223226 ignore : Optional [List [str ]] = typer .Option (
224227 None , "--ignore" , help = "Directories to ignore (repeatable)"
225228 ),
229+ branch : Optional [str ] = typer .Option (
230+ None , "--branch" , help = "Branch to associate with this index (auto-detected from the cloned checkout when omitted)"
231+ ),
226232) -> None :
227233 """Clone a git repository and index it into the knowledge graph."""
228234 from .project import Project
@@ -233,22 +239,22 @@ def index_repo(
233239 import io
234240 import contextlib
235241 with contextlib .redirect_stdout (io .StringIO ()):
236- project = Project .from_git_repository (url )
242+ project = Project .from_git_repository (url , branch = branch )
237243 graph = project .analyze_sources (ignore = list (ignore ) if ignore else [])
238244 stats = graph .stats ()
239245 except Exception as e :
240246 _json_error (str (e ))
241247
242- _stderr (f"Done — { stats ['node_count' ]} nodes, { stats ['edge_count' ]} edges" )
243- _json_out ({"status" : "ok" , "repo" : project .name , ** stats })
248+ _stderr (f"Done — { stats ['node_count' ]} nodes, { stats ['edge_count' ]} edges (branch= { project . branch } ) " )
249+ _json_out ({"status" : "ok" , "repo" : project .name , "branch" : project . branch , ** stats })
244250
245251
246252# ── list ───────────────────────────────────────────────────────────────
247253
248254
249255@app .command ("list" )
250256def list_repos () -> None :
251- """List all indexed repositories ."""
257+ """List all indexed (project, branch) pairs ."""
252258 from .graph import get_repos
253259
254260 try :
@@ -259,6 +265,30 @@ def list_repos() -> None:
259265 _json_out ({"repos" : repos })
260266
261267
268+ # ── migrate ────────────────────────────────────────────────────────────
269+
270+
271+ @app .command ("migrate" )
272+ def migrate (
273+ dry_run : bool = typer .Option (False , "--dry-run" , help = "Print actions without performing them" ),
274+ ) -> None :
275+ """Promote legacy (pre-T17) graphs and Redis keys into the per-branch namespace.
276+
277+ Renames each legacy ``<project>`` graph to ``code:<project>:_default``,
278+ each ``{project}_info`` Redis key to ``{project}:_default_info``, and
279+ each ``{project}_git`` graph to ``{project}:_default_git``. Idempotent.
280+ """
281+
282+ from .migrations .per_branch import run_migration
283+
284+ try :
285+ result = run_migration (dry_run = dry_run )
286+ except Exception as e :
287+ _json_error (str (e ))
288+
289+ _json_out (result )
290+
291+
262292# ── search ─────────────────────────────────────────────────────────────
263293
264294
@@ -268,18 +298,24 @@ def search(
268298 repo : Optional [str ] = typer .Option (
269299 None , "--repo" , help = "Repository name (defaults to CWD name)"
270300 ),
301+ branch : Optional [str ] = typer .Option (
302+ None , "--branch" , help = "Branch (auto-detected from CWD; '_default' for non-git paths)"
303+ ),
271304) -> None :
272305 """Search for entities by prefix (full-text search)."""
273306 from .graph import Graph
307+ from .project import detect_branch
274308
275309 name = _default_repo (repo )
310+ if branch is None :
311+ branch = detect_branch (Path .cwd ())
276312 try :
277- g = Graph (name )
313+ g = Graph (name , branch = branch )
278314 results = g .prefix_search (query )
279315 except Exception as e :
280316 _json_error (str (e ))
281317
282- _json_out ({"repo" : name , "results" : results })
318+ _json_out ({"repo" : name , "branch" : branch , " results" : results })
283319
284320
285321# ── neighbors ──────────────────────────────────────────────────────────
@@ -297,18 +333,24 @@ def neighbors(
297333 label : Optional [str ] = typer .Option (
298334 None , "--label" , help = "Filter by destination label (e.g. Function, Class)"
299335 ),
336+ branch : Optional [str ] = typer .Option (
337+ None , "--branch" , help = "Branch (auto-detected from CWD; '_default' for non-git paths)"
338+ ),
300339) -> None :
301340 """Get neighboring entities of the given node(s)."""
302341 from .graph import Graph
342+ from .project import detect_branch
303343
304344 name = _default_repo (repo )
345+ if branch is None :
346+ branch = detect_branch (Path .cwd ())
305347 try :
306- g = Graph (name )
348+ g = Graph (name , branch = branch )
307349 result = g .get_neighbors (node_ids , rel = rel , lbl = label )
308350 except Exception as e :
309351 _json_error (str (e ))
310352
311- _json_out ({"repo" : name , ** result })
353+ _json_out ({"repo" : name , "branch" : branch , ** result })
312354
313355
314356# ── paths ──────────────────────────────────────────────────────────────
@@ -321,18 +363,24 @@ def paths(
321363 repo : Optional [str ] = typer .Option (
322364 None , "--repo" , help = "Repository name (defaults to CWD name)"
323365 ),
366+ branch : Optional [str ] = typer .Option (
367+ None , "--branch" , help = "Branch (auto-detected from CWD; '_default' for non-git paths)"
368+ ),
324369) -> None :
325370 """Find call-chain paths between two nodes."""
326371 from .graph import Graph
372+ from .project import detect_branch
327373
328374 name = _default_repo (repo )
375+ if branch is None :
376+ branch = detect_branch (Path .cwd ())
329377 try :
330- g = Graph (name )
378+ g = Graph (name , branch = branch )
331379 result = g .find_paths (src , dest )
332380 except Exception as e :
333381 _json_error (str (e ))
334382
335- _json_out ({"repo" : name , "paths" : result })
383+ _json_out ({"repo" : name , "branch" : branch , " paths" : result })
336384
337385
338386# ── info ───────────────────────────────────────────────────────────────
@@ -343,20 +391,26 @@ def info(
343391 repo : Optional [str ] = typer .Option (
344392 None , "--repo" , help = "Repository name (defaults to CWD name)"
345393 ),
394+ branch : Optional [str ] = typer .Option (
395+ None , "--branch" , help = "Branch (auto-detected from CWD; '_default' for non-git paths)"
396+ ),
346397) -> None :
347398 """Show repository statistics and metadata."""
348399 from .graph import Graph
349400 from .info import get_repo_info
401+ from .project import detect_branch
350402
351403 name = _default_repo (repo )
404+ if branch is None :
405+ branch = detect_branch (Path .cwd ())
352406 try :
353- g = Graph (name )
407+ g = Graph (name , branch = branch )
354408 stats = g .stats ()
355- metadata = get_repo_info (name ) or {}
409+ metadata = get_repo_info (name , branch ) or {}
356410 except Exception as e :
357411 _json_error (str (e ))
358412
359- _json_out ({"repo" : name , ** stats , "metadata" : metadata })
413+ _json_out ({"repo" : name , "branch" : branch , ** stats , "metadata" : metadata })
360414
361415
362416if __name__ == "__main__" :
0 commit comments