How to Track Real Developer Activity on GitHub: Beyond 'Recently Updated'
Keeping a pulse on active development is fundamental for any high-performing engineering team. For many, GitHub's issue tracker is the central hub for managing work. However, a recent discussion in the GitHub Community (Discussion #206757) highlighted a critical gap: the inability to sort issues by their commit timestamp. This isn't just a minor inconvenience; it significantly impacts how teams monitor developer activity and prioritize work, potentially obscuring issues that are actively being coded but lack recent comments.
As Senior Tech Writer at devActivity, I see this challenge frequently. The standard 'Recently updated' sort often misses the most crucial signal of progress: a linked commit. This can lead to skewed perceptions of engineering performance and inefficient resource allocation.
The Challenge: When "Recently Updated" Falls Short
GitHub's default 'Recently updated' sort order is a good start, but it falls short for many use cases. It primarily tracks explicit mutations to an issue: new comments, description edits, label changes, milestone adjustments, or state transitions (open/close). What it deliberately excludes are commits that reference an issue, even if that commit directly addresses the issue's core problem.
For individual developers managing a personal cross-repository TODO list, or for product managers trying to gauge true progress, the most relevant update is often a linked commit, not a new comment. This means issues with active code changes might appear dormant, hindering efficient workflow and accurate insights into real-time developer activity.
The reason for this behavior lies deep within GitHub's architecture. The updated_at attribute on an Issue object is only incremented for direct record mutations. When a commit references an issue (e.g., #123 or fixes #123), GitHub records a ReferencedEvent in the issue's timeline stream. However, it intentionally does not update the parent issue's updated_at timestamp. This design choice is pragmatic: it prevents historical branch pushes or repository rebases from unexpectedly bumping hundreds of old, dormant issues to the top of everyone's notifications and search feeds. While logical from an infrastructure perspective, it creates a visibility gap for teams focused on active code delivery.
The Impact on Productivity and Delivery
This architectural decision, while preventing notification floods, creates tangible problems for teams focused on productivity and delivery:
- Misleading Prioritization: Issues with active development (linked commits) might sink in the 'Recently updated' list, leading to misinformed prioritization decisions by product and project managers.
- Inaccurate Status Reporting: Delivery managers and CTOs may receive an incomplete picture of project progress if issues with recent code changes are not easily identifiable.
- Reduced Developer Efficiency: Developers themselves struggle to maintain an accurate personal 'TODO' list spanning multiple repositories, as their most recent work isn't reflected in the primary issue view.
- Hindered Engineering Performance Analysis: Without a clear way to track commit-linked activity, it becomes harder to genuinely assess team velocity and identify bottlenecks in the development lifecycle.
Community-Driven Solutions for Enhanced Tracking
The good news is that the GitHub community, including insightful contributors like amasen02, has devised practical workarounds to bridge this visibility gap and gain better insight into commit-related developer activity. These solutions empower teams to surface issues based on actual code changes, despite GitHub's default sorting limitations.
1. Instant Local Git Command
For quick, repository-specific insights, you don't always need complex APIs. If you have the repository cloned locally, a simple Git command can instantly extract issues ordered by the exact commit author date:
git log --all --grep="#[0-9]\+" --date=iso-strict --pretty=format:"%ad | commit %h | %s"
This command immediately outputs all commits that reference an issue, ordered chronologically by their commit timestamp. It's a powerful, zero-API-limit solution for individual developers.
2. Querying via GitHub GraphQL API
For programmatic access across remote issues, the GitHub GraphQL API offers a robust solution. You can inspect an issue's timeline specifically for ReferencedEvent types to find the most recent commit activity. This allows for building custom dashboards or integrations that surface issues based on code changes.
Here's a simplified GraphQL query example:
query($owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issues(first: 20, states: OPEN) { nodes { number title timelineItems(last: 1, itemTypes: [REFERENCED_EVENT]) { nodes { ... on ReferencedEvent { createdAt commit { oid message committedDate } } } } } } }}
This query retrieves the latest ReferencedEvent for open issues, providing the commit details and its timestamp. While this requires some API development, it offers unparalleled flexibility for custom tooling.
3. GitHub Projects (v2) Automation
For teams leveraging GitHub Projects (v2), there's an opportunity for automation. When linking pull requests to issues, Projects tracks the PR's updated and merged timestamps. To get closer to commit-level tracking, you can:
- Sort by Linked Pull Request Status: In your Project table view, sort by the status of linked pull requests, which often correlates with recent code activity.
- Automate Custom Fields: Use GitHub Actions on
pushevents to write thegithub.event.head_commit.timestampto a custom Project date field, perhaps named "Last Commit". This effectively brings commit-level timestamps into your project management view.
Building Your Own "Commit-Aware" Issue Tracker
As nexushoratio, the original discussion author, discovered, building a custom solution, while exposing the complexity of event types, is entirely feasible. Their Python script, though a "toy code" example lacking error checking and pagination, demonstrates the principle:
def _repos(user: string): url = f'https://api.github.com/users/{user}/repos' with urllib.request.urlopen(url) as resp: for data in json.loads(resp.read()): yield data['url']
def _issues(repo_url, assignee): url = f'{repo_url}/issues?assignee={assignee}' with urllib.request.urlopen(url) as resp: for data in json.loads(resp.read()): yield data
def _events(events_url): with urllib.request.urlopen(events_url) as resp: for data in json.loads(resp.read()): if data['event'] not in ('blocked_by_added', 'labeled', 'blocking_added', 'blocking_removed', 'pinned', 'renamed'): yield data
def user(user_name) -> int: issues = list() for repo_url in _repos(user_name): for issue in _issues(repo_url, user_name): events = list() for event in _events(issue['events_url']): events.append(( datetime.datetime.fromisoformat(event['created_at']).timestamp(), event['event'], event['actor']['login'], )) event = max(events) issues.append((event, issue['html_url'])) for issue in sorted(issues): print(issue)
This script iterates through user repositories, fetches assigned issues, and then retrieves their events, filtering for relevant activity to determine the "last updated" based on a broader definition. While raw API calls can be complex due to rate limits and pagination, this approach highlights the power of custom tooling to tailor GitHub's data to specific team needs.
Elevating Your Engineering Performance
The inability to sort GitHub issues by commit timestamp is a real limitation, but it's not insurmountable. By understanding GitHub's architecture and leveraging the powerful tools and APIs available, engineering teams, product managers, and CTOs can build or adopt solutions that provide a more accurate and timely view of developer activity.
Implementing these workarounds can significantly improve how you conduct a sprint retrospective meeting, gain insights into true progress, and ultimately enhance overall engineering performance. Don't let default settings obscure your team's hard work; empower your workflow with commit-aware issue tracking.
