Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 63 additions & 41 deletions git_context/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@
Dump project structure, git log, file contents, and branch topology
in one optimized prompt-ready block.

Usage: git context [--depth N] [--files] [--log N] [--output file] [--dir <path>]
Usage: git context [--depth N] [--files] [--log N] [--output file] [--dir <path>] [--json]
"""

import argparse
import os
import subprocess
import sys
import fnmatch
import json
from pathlib import Path
from datetime import datetime

Expand Down Expand Up @@ -128,6 +129,7 @@ def main():
p.add_argument('--log', type=int, default=20, help='Number of recent commits (default: 20, 0=skip)')
p.add_argument('--output', '-o', help='Write to file instead of stdout')
p.add_argument('--dir', default=os.getcwd(), help='Target directory (default: cwd)')
p.add_argument('--json', action='store_true', help='Output in JSON format')
args = p.parse_args()

target = os.path.abspath(args.dir)
Expand All @@ -136,54 +138,74 @@ def main():
sys.exit(1)

repo_name = os.path.basename(target)
sections = []
sections.append(f"# git-context: {repo_name}")
sections.append(f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
sections.append(f"Path: {target}")
sections.append("")

# Git info
branch = run(["git", "rev-parse", "--abbrev-ref", "HEAD"], target)
remote = run(["git", "remote", "get-url", "origin"], target)
sections.append(f"## Git Info\n- Branch: `{branch}`")
sections.append(f"- Remote: {remote}")

# Collect data
git_info = {
"branch": run(["git", "rev-parse", "--abbrev-ref", "HEAD"], target),
"remote": run(["git", "remote", "get-url", "origin"], target),
}

has_unstaged = run(["git", "diff", "--stat"], target)
has_staged = run(["git", "diff", "--cached", "--stat"], target)
status = ""
if has_unstaged: status += f"\n- Unstaged changes: {has_unstaged.split(chr(10))[-1]}"
if has_staged: status += f"\n- Staged changes: {has_staged.split(chr(10))[-1]}"
status_msg = ""
if has_unstaged: status_msg += f"Unstaged changes: {has_unstaged.split(chr(10))[-1]} "
if has_staged: status_msg += f"Staged changes: {has_staged.split(chr(10))[-1]} "
if not has_unstaged and not has_staged:
status += "\n- Working tree: clean"
sections.append(status)

# Recent commits
status_msg = "Working tree: clean"

git_info["status"] = status_msg.strip()

log_data = []
if args.log > 0:
log = run(["git", "log", f"--max-count={args.log}", "--oneline", "--graph",
"--pretty=format:%h %d %s (%an, %ar)"], target)
if log:
sections.append(f"\n## Recent Commits (last {args.log})")
sections.append(f"```\n{log}\n```")

# Branch topology
branches = run(["git", "branch", "-a"], target)
if branches:
sections.append("\n## Branches")
sections.append(f"```\n{branches}\n```")

# Directory tree
raw_log = run(["git", "log", f"--max-count={args.log}", "--oneline", "--graph",
"--pretty=format:%h %d %s (%an, %ar)"], target)
if raw_log:
log_data = raw_log.splitlines()

branches_data = run(["git", "branch", "-a"], target)

tree_out = tree(target, ignored=DEFAULT_IGNORE, depth=args.depth)
sections.append(f"\n## Project Structure (depth={args.depth})")
sections.append(f"```\n{tree_out}\n```")

# File contents

contents_data = ""
if args.files:
contents = file_contents(target)
if contents:
contents_data = file_contents(target)

# Output logic
if args.json:
data = {
"repo_name": repo_name,
"generated_at": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
"path": target,
"git_info": git_info,
"recent_commits": log_data,
"branches": branches_data,
"project_structure": tree_out,
"file_contents": contents_data
}
output = json.dumps(data, indent=2)
else:
sections = [
f"# git-context: {repo_name}",
f"Generated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}",
f"Path: {target}",
"",
f"## Git Info\n- Branch: `{git_info['branch']}`",
f"- Remote: {git_info['remote']}",
f"Status: {git_info['status']}",
"",
]
if log_data:
sections.append(f"## Recent Commits (last {args.log})")
sections.append(f"```\n{''.join(log_data)}\n```")
if branches_data:
sections.append(f"\n## Branches")
sections.append(f"```\n{branches_data}\n```")
sections.append(f"\n## Project Structure (depth={args.depth})")
sections.append(f"```\n{tree_out}\n```")
if contents_data:
sections.append("\n## File Contents")
sections.append(contents)

output = "\n".join(sections)
sections.append(contents_data)
output = "\n".join(sections)

if args.output:
Path(args.output).write_text(output)
Expand Down