-
-
Notifications
You must be signed in to change notification settings - Fork 6.4k
Use commit author date for heatmap instead of push date #36469
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Use commit author date for heatmap instead of push date #36469
Conversation
When commits are made locally over multiple days and then pushed at once, the contribution heatmap now displays them on their actual author dates rather than the push date. Changes: - Add OriginalUnix field to Action model to store the original content timestamp - Set OriginalUnix to the earliest commit author date when creating push actions - Update heatmap query to use COALESCE(original_unix, created_unix) - Add database migration for the new column Fixes go-gitea#14051 Co-Authored-By: Claude Opus 4.5 <[email protected]>
0ee2edf to
974f890
Compare
Instead of creating a single action record with all commits grouped under the earliest date, this creates separate action records for each unique date. Each commit now appears on its actual author date in the heatmap. The original_unix field stores the actual commit timestamp (not truncated to midnight) so the frontend can properly display it in the user's timezone. Co-Authored-By: Claude Opus 4.5 <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adjusts contribution heatmap bucketing to use commit author timestamps (when available) rather than push timestamps, fixing multi-day local commit batches showing up on a single push day.
Changes:
- Adds
OriginalUnixtoActionand a DB migration to persist original timestamps. - Splits push (and mirror sync push) actions into per-day action records and stores an original commit timestamp on each.
- Updates the heatmap grouping query to prefer
original_unixviaCOALESCE(NULLIF(original_unix, 0), created_unix).
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| services/feed/notifier.go | Creates per-day action records for pushes/sync pushes and sets OriginalUnix based on commit timestamps. |
| models/migrations/v1_26/v326.go | Adds original_unix column (indexed) to the action table. |
| models/migrations/migrations.go | Registers migration 326. |
| models/activities/user_heatmap.go | Uses original_unix (fallback created_unix) for heatmap grouping. |
| models/activities/action.go | Adds OriginalUnix field to the Action model. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Use original_unix if available (for commit actions, this is the commit author date), | ||
| // otherwise fall back to created_unix (the push/action timestamp). | ||
| groupBy := "COALESCE(NULLIF(original_unix, 0), created_unix) / 900 * 900" | ||
| groupByName := "timestamp" // We need this extra case because mssql doesn't allow grouping by alias | ||
| switch { | ||
| case setting.Database.Type.IsMySQL(): | ||
| groupBy = "created_unix DIV 900 * 900" | ||
| groupBy = "COALESCE(NULLIF(original_unix, 0), created_unix) DIV 900 * 900" |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The heatmap query now groups by COALESCE(NULLIF(original_unix, 0), created_unix), but it still filters rows using created_unix > ... later in this function. That means a newly-created action with an old original_unix can produce heatmap buckets far outside the intended (366+7)-day window. Consider filtering on the same coalesced timestamp (or an equivalent condition that respects original_unix when present) to keep the returned timestamps within the heatmap range.
| // Use original_unix if available (for commit actions, this is the commit author date), | ||
| // otherwise fall back to created_unix (the push/action timestamp). | ||
| groupBy := "COALESCE(NULLIF(original_unix, 0), created_unix) / 900 * 900" | ||
| groupByName := "timestamp" // We need this extra case because mssql doesn't allow grouping by alias | ||
| switch { | ||
| case setting.Database.Type.IsMySQL(): | ||
| groupBy = "created_unix DIV 900 * 900" | ||
| groupBy = "COALESCE(NULLIF(original_unix, 0), created_unix) DIV 900 * 900" |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is existing test coverage for the heatmap query, but no tests asserting the new original_unix behavior (preferring commit author dates and handling mixed created_unix/original_unix). Adding/adjusting a unit test fixture with original_unix != 0 and a different created_unix would help prevent regressions.
services/feed/notifier.go
Outdated
| // Create separate action records for each date | ||
| for _, dayCommits := range commitsByDate { | ||
| // Create a PushCommits struct for this day's commits | ||
| dayPushCommits := &repository.PushCommits{ |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for _, dayCommits := range commitsByDate iterates over a map, so the order of created action records is nondeterministic. This can lead to unstable ordering in activity feeds/notifications for multi-day pushes. Consider iterating over sorted day keys (and optionally sorting commits within each day) to make action creation deterministic.
services/feed/notifier.go
Outdated
| // Group commits by date (truncated to day) so each day's commits appear | ||
| // on the correct date in the heatmap, not all on the push date. | ||
| commitsByDate := make(map[int64][]*repository.PushCommit) | ||
| for _, commit := range commits.Commits { | ||
| // Truncate to start of day (UTC) | ||
| dayTimestamp := commit.Timestamp.UTC().Truncate(24 * time.Hour).Unix() | ||
| commitsByDate[dayTimestamp] = append(commitsByDate[dayTimestamp], commit) | ||
| } |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit grouping and per-day action creation logic is duplicated between PushCommits and SyncPushCommits. Consider extracting the grouping + per-day action emission into a shared helper to reduce duplication and keep future fixes (eg ordering, timestamp selection) consistent.
services/feed/notifier.go
Outdated
| // Create separate action records for each date | ||
| for _, dayCommits := range commitsByDate { | ||
| dayPushCommits := &repository.PushCommits{ | ||
| Commits: dayCommits, |
Copilot
AI
Jan 30, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for _, dayCommits := range commitsByDate iterates over a map, so the order of created action records is nondeterministic. This can lead to unstable ordering in activity feeds/notifications for multi-day mirror sync pushes. Consider iterating over sorted day keys to make action creation deterministic.
- Fix heatmap query to filter by COALESCE(original_unix, created_unix) instead of created_unix, so old commits pushed recently stay in range - Extract shared groupCommitsByDay() and notifyPushActions() helpers to deduplicate logic between PushCommits and SyncPushCommits - Sort day keys for deterministic action creation order - Add test fixture (action id:10) with original_unix != created_unix and update heatmap test expectations to verify original_unix is used Co-Authored-By: Claude Opus 4.5 <[email protected]>
The new action fixture (id:10) for testing original_unix in heatmap also appears in feed queries for user 2 and repo 2. Update feed test expectations to account for the additional action record. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Update TestUserHeatmap to expect both the original action and the new action with original_unix, which appears at a different timestamp in the heatmap. Co-Authored-By: Claude Opus 4.5 <[email protected]>
Summary
When commits are made locally over multiple days and then pushed at once, the contribution heatmap currently displays all commits on the push date rather than their actual author dates. This PR fixes that behavior.
Changes:
OriginalUnixfield to theActionmodel to store the original commit timestampCOALESCE(NULLIF(original_unix, 0), created_unix)to prefer the original date when availableHow it works
When a push contains commits from multiple days, separate action records are created for each date. Each commit now appears on its actual author date in the heatmap, matching user expectations and GitHub's behavior.
Backward Compatibility
OriginalUnixwill continue to usecreated_unix(the push date) viaCOALESCETest Plan
OriginalUnix) still display correctlyFixes #36471
Related to #14051 / #11861 (locked)