Skip to content

feat(cc): add git branch and dirty status to statusline#202

Merged
AnnatarHe merged 2 commits intomainfrom
feat/cc-statusline-git-info
Jan 6, 2026
Merged

feat(cc): add git branch and dirty status to statusline#202
AnnatarHe merged 2 commits intomainfrom
feat/cc-statusline-git-info

Conversation

@AnnatarHe
Copy link
Copy Markdown
Contributor

Summary

  • Add git branch name and dirty status to the cc statusline output
  • Git info is displayed first in the statusline: 🌿 main* | 🤖 model | 💰 $x | ...
  • Branch name shown with * suffix when repo has uncommitted changes
  • Uses go-git library for pure Go git detection (no external process)

Changes

  • model/cc_statusline_types.go: Add WorkingDirectory to input
  • daemon/socket.go: Extend CCInfoRequest/CCInfoResponse with git fields
  • daemon/git.go: New module for git branch/dirty detection
  • daemon/git_test.go: Tests for git detection
  • commands/cc_statusline.go: Display git info first in output

Test plan

  • Build passes (go build ./...)
  • Git detection tests pass
  • CCInfo handler tests updated and pass
  • Client tests updated and pass

🤖 Generated with Claude Code

Add git branch name and dirty status to the cc statusline output.
The git information is displayed first in the statusline, showing
the branch name with an asterisk suffix if there are uncommitted changes.

- Add WorkingDirectory field to CCStatuslineInput (from Claude Code)
- Extend CCInfoRequest/Response with git info fields
- Create daemon/git.go using go-git for branch/dirty detection
- Update statusline format: 🌿 main* | 🤖 model | 💰 $x | ...

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant enhancement to the cc statusline command by integrating real-time Git repository status directly into its output. Developers can now quickly see their current Git branch and whether their working directory has uncommitted changes, providing immediate context alongside other cc metrics. This integration is achieved through a new pure Go Git detection module, ensuring efficient and self-contained operation.

Highlights

  • Git Status Integration: The cc statusline output now includes the current Git branch name and an indicator for uncommitted changes (dirty status).
  • Prominent Display: Git information is displayed first in the statusline, using a '🌿' emoji for visual clarity, e.g., 🌿 main* | 🤖 model | 💰 $x | ....
  • Pure Go Git Detection: The feature utilizes the go-git library for Git detection, ensuring a pure Go implementation without relying on external git processes.
  • Daemon Enhancement: The daemon now handles requests for Git information, retrieving it based on the provided working directory and including it in the CCInfoResponse.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request adds a great new feature to the statusline, showing the current Git branch and dirty status. The implementation using go-git is a good choice to avoid shelling out to an external git process. The code is well-structured, with the logic cleanly separated into a new daemon/git.go module and integrated into the existing daemon and client code. The addition of comprehensive tests for the new git functionality is also excellent.

I have a few suggestions for improvement:

  1. In daemon/git.go, errors encountered while fetching git information are silently ignored. Adding debug logging would make it easier to diagnose issues in the future.
  2. The new tests in daemon/git_test.go could be made more robust by checking for errors during the test setup phase.
  3. The payload parsing in daemon/socket.go could be made more robust.

A general consideration is the performance of go-git's Worktree.Status() method, which can be slow on very large repositories. Given the tight 50ms timeout for the daemon request, this could potentially cause timeouts. This is a trade-off for using a pure Go implementation, but it's something to be aware of.

Comment thread daemon/git.go
Comment on lines +31 to +43
head, err := repo.Head()
if err == nil {
info.Branch = head.Name().Short()
}

// Check dirty status by examining worktree status
worktree, err := repo.Worktree()
if err == nil {
status, err := worktree.Status()
if err == nil {
info.Dirty = !status.IsClean()
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The errors from repo.Head(), repo.Worktree(), and worktree.Status() are silently ignored. While this ensures the function doesn't fail for the statusline, it can make debugging issues with git state detection difficult. For example, if getting the branch name fails for an unexpected reason, it will just be blank with no indication of why. Consider adding debug-level logging for these errors. You will also need to add import "log/slog" to this file.

head, err := repo.Head()
if err != nil {
	slog.Debug("failed to get git HEAD", "err", err, "dir", workingDir)
} else {
	info.Branch = head.Name().Short()
}

// Check dirty status by examining worktree status
worktree, err := repo.Worktree()
if err != nil {
	slog.Debug("failed to get git worktree", "err", err, "dir", workingDir)
} else {
	status, err := worktree.Status()
	if err != nil {
		slog.Debug("failed to get worktree status", "err", err, "dir", workingDir)
	} else {
		info.Dirty = !status.IsClean()
	}
}

Comment thread daemon/git_test.go
Comment on lines +59 to +60
exec.Command("git", "-C", s.tempDir, "config", "user.email", "test@test.com").Run()
exec.Command("git", "-C", s.tempDir, "config", "user.name", "Test User").Run()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The exec.Command calls to configure the git user are not checking for errors. If these commands fail, the subsequent git commit will also fail, but the root cause will be less obvious. It's good practice to assert that setup commands in tests execute successfully to make tests more robust and easier to debug. This applies to the other test cases in this file as well.

Suggested change
exec.Command("git", "-C", s.tempDir, "config", "user.email", "test@test.com").Run()
exec.Command("git", "-C", s.tempDir, "config", "user.name", "Test User").Run()
assert.NoError(s.T(), exec.Command("git", "-C", s.tempDir, "config", "user.email", "test@test.com").Run())
assert.NoError(s.T(), exec.Command("git", "-C", s.tempDir, "config", "user.name", "Test User").Run())

Comment thread daemon/socket.go
Comment on lines 204 to 213
timeRange := CCInfoTimeRangeToday
var workingDir string
if payload, ok := msg.Payload.(map[string]interface{}); ok {
if tr, ok := payload["timeRange"].(string); ok {
timeRange = CCInfoTimeRange(tr)
}
if wd, ok := payload["workingDirectory"].(string); ok {
workingDir = wd
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Parsing the payload using type assertions on a map[string]interface{} is fragile. For example, if the client sends a non-string value for timeRange, it will be silently ignored. A more robust approach is to unmarshal the payload into the CCInfoRequest struct. This ensures proper type handling and validation. This pattern is already used in the tests (e.g., daemon/cc_info_handler_test.go:324-326).

Suggested change
timeRange := CCInfoTimeRangeToday
var workingDir string
if payload, ok := msg.Payload.(map[string]interface{}); ok {
if tr, ok := payload["timeRange"].(string); ok {
timeRange = CCInfoTimeRange(tr)
}
if wd, ok := payload["workingDirectory"].(string); ok {
workingDir = wd
}
}
var req CCInfoRequest
req.TimeRange = CCInfoTimeRangeToday // Default
if payload, ok := msg.Payload.(map[string]interface{}); ok {
if b, err := json.Marshal(payload); err == nil {
// This is more robust than type assertions.
// Ignore unmarshal error, fields will be zero values if it fails.
_ = json.Unmarshal(b, &req)
}
}
timeRange := req.TimeRange
workingDir := req.WorkingDirectory

Update test function signatures to match new formatStatuslineOutput
and getDaemonInfoWithFallback APIs. Add tests for git branch display
including dirty branch indicator.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 6, 2026

Codecov Report

❌ Patch coverage is 87.50000% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
commands/cc_statusline.go 80.95% 4 Missing ⚠️
daemon/socket.go 66.66% 1 Missing and 1 partial ⚠️
Flag Coverage Δ
unittests 37.42% <87.50%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
daemon/client.go 85.71% <100.00%> (+0.34%) ⬆️
daemon/git.go 100.00% <100.00%> (ø)
daemon/socket.go 64.70% <66.66%> (+0.10%) ⬆️
commands/cc_statusline.go 61.60% <80.95%> (+4.60%) ⬆️

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@AnnatarHe AnnatarHe merged commit a972290 into main Jan 6, 2026
3 checks passed
@AnnatarHe AnnatarHe deleted the feat/cc-statusline-git-info branch January 6, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant