Skip to content

fix: merge contributions by commit email - #18

Open
0xbrayo wants to merge 1 commit into
ActivityWatch:masterfrom
0xbrayo:fix/merge-authors-by-email
Open

fix: merge contributions by commit email#18
0xbrayo wants to merge 1 commit into
ActivityWatch:masterfrom
0xbrayo:fix/merge-authors-by-email

Conversation

@0xbrayo

@0xbrayo 0xbrayo commented Sep 8, 2026

Copy link
Copy Markdown
Member

Fixes #9

Author names were only merged through the hardcoded author_merges list, so the same person showed up as several rows whenever they had committed under different spellings of their name.

What changed

  • Commits that share an author email are now merged into a single author. Grouping is transitive (ab, bc ⇒ one author) and is computed across all repos at once, so a person also gets a single row in the merged total table instead of a different winner per repo.
  • The displayed name is the spelling with the most commits, ties broken by name so the output stays deterministic.
  • Emails that identify a git/GitHub default rather than a person (noreply@github.com, you@example.com, ...) and malformed ones are ignored, so they can't merge two people together.
  • The manual author_merges list is kept, for the aliases that don't share a commit email (dependabot-preview[bot], the Erik Bjäreholt mojibake, ...).

Two related bugs fixed along the way:

  • The blame lines of a merged-away alias were dropped instead of being attributed to the author it was merged into (blame is looked up by name, and the alias no longer existed under that name).
  • Two names that only differed by unicode normalization overwrote each other in authorInfos instead of being merged, losing one of them.

Effect on the tables

Running against the currently cloned repos, this merges (among others):

merged away into
brayo Brayo
2e3s Demmie
wojnilowicz Łukasz Wojniłowicz
Erik Bjareholt, Erik Bjäreholt Erik Bjäreholt
nikanar Nikana
Bill-linux Bill Ang Li
kewde Kewde
Zach S Zach Strout
Ayush Ayush Singh
yuh yuhldr
Nicolae/nicolae Nicolae Stroncea
the two unicode spellings of Måns Magnusson one row

Nothing else in the generated tables changes, apart from the blame percentages that shift because alias blame lines are no longer dropped.

Testing

  • make typecheck passes.
  • New tests/test_main.py covers the email normalization, the (transitive) grouping, the canonical-name choice and its determinism, and the merging in get_authorInfos — including that the manual alias list and the unicode normalization still apply. It needs no network or GitHub token.
  • Also ran the generator over aw-client, aw-qt and awatcher and diffed the produced tables against the ones from master to confirm the only changes are the intended merges.

Author names were only merged through a hardcoded list of aliases, so the
same person showed up as several rows whenever they had committed under
different spellings of their name ("Brayo" and "brayo", "2e3s" and
"Demmie", "wojnilowicz" and "Łukasz Wojniłowicz", ...).

Commits sharing an author email are now merged into a single author,
transitively and across all repos at once, so a person also gets a single
row in the "total" table. The name with the most commits wins, with ties
broken by name to keep the output deterministic. Emails that identify a
git default rather than a person are ignored, and the manual alias list is
kept for the aliases that don't share an email (dependabot, mojibake, ...).

Also fixes two related bugs: the blame lines of a merged-away alias were
dropped instead of being attributed to the author it merged into, and two
names that only differed by unicode normalization overwrote each other
instead of being merged.

Fixes ActivityWatch#9
@greptile-apps

greptile-apps Bot commented Sep 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR merges contributor identities that share commit emails across repositories, chooses a deterministic canonical display name, preserves manual aliases, and remaps blame from merged aliases.

  • Adds normalized email extraction and transitive identity grouping.
  • Applies one global alias map to individual and total tables.
  • Preserves statistics and blame when aliases or Unicode-equivalent names are merged.
  • Adds focused unit coverage for normalization, grouping, canonical-name selection, and statistics merging.
  • The email validity barrier remains too permissive and can merge unrelated contributors through malformed or shared defaults.

Confidence Score: 4/5

The PR should not merge until email filtering prevents malformed and shared default addresses from collapsing unrelated contributor rows.

Accepted email values become transitive identity keys, but the current check admits any non-blocklisted string containing @; a shared junk/default value therefore combines unrelated contributors’ commits and blame.

Files Needing Attention: src/contributor_stats/main.py

Important Files Changed

Filename Overview
src/contributor_stats/main.py Adds cross-repository email-based alias resolution and blame remapping, but accepts malformed and unrecognized shared/default emails as identity keys.
tests/test_main.py Adds useful deterministic unit coverage, though it does not cover malformed strings containing @ or shared default addresses outside the exact blocklist.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    A[Git histories across repositories] --> B[Extract mailmap-resolved names and emails]
    B --> C[Normalize and filter emails]
    C --> D[Group names transitively by shared email]
    D --> E[Choose canonical name by commit count]
    E --> F[Merge per-repository statistics]
    E --> G[Remap alias blame lines]
    F --> H[Repository tables]
    G --> H
    H --> I[Merged total table]
Loading

Reviews (1): Last reviewed commit: "fix: merge contributions by commit email" | Re-trigger Greptile

Comment on lines +75 to +77
email = email.strip().lower()
if "@" not in email or email in GENERIC_EMAILS:
return ""

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Invalid emails merge authors

normalize_email accepts every non-blocklisted string containing @, including malformed values such as a@@b and shared defaults such as root@build-host. These accepted values are used directly for transitive author grouping. If unrelated contributors share one of these values, their commits and blame are incorrectly combined into one row. Validate the address structure and reject generic local or shared patterns instead of relying on four exact strings.

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.

Merge contributions by email

1 participant