Skip to content

Wrong attrs.git_file_{created,modified}_year when traversal encounters merge commit #203

@xiangjinwu

Description

@xiangjinwu

Description

hawkeye_fmt::git::resolve_file_attrs relies on head.ancestors().all() to traverse the commits in a certain order and compare their working trees. However, when the git history is not linear and involves merge-commits, improper traversal orders can leads to wrong attrs.git_file_{created,modified}_year.

Reproduce

#!/usr/bin/env bash

set -euo pipefail

git init
cat > licenserc.toml <<EOF
inlineHeader = "{{attrs.git_file_created_year}} - {{attrs.git_file_modified_year}}"

excludes = ["licenserc.toml"]

[git]
ignore = "enable"
attrs = "enable"
EOF
git add licenserc.toml
echo foo > COMMON1.md
echo foo > COMMON2.md
git add COMMON1.md
git add COMMON2.md
GIT_COMMITTER_DATE="2025-12-15T00:00:00Z" git commit -m 'init'

echo foo >> COMMON1.md
GIT_COMMITTER_DATE="2025-12-22T00:00:00Z" git commit -a -m 'base'

git branch wip

echo "// 2025 - 2025" > A.rs
git add A.rs
GIT_COMMITTER_DATE="2025-12-30T00:00:00Z" git commit -m 'mA2025'

echo "// 2026 - 2026" > B.rs
git add B.rs
GIT_COMMITTER_DATE="2026-01-05T00:00:00Z" git commit -m 'mB2026'

echo foo >> COMMON1.md
GIT_COMMITTER_DATE="2026-01-07T00:00:00Z" git commit -a -m 'dummy'

echo foo >> COMMON1.md
GIT_COMMITTER_DATE="2026-01-08T00:00:00Z" git commit -a -m 'random'

git checkout wip
echo foo >> COMMON2.md
GIT_COMMITTER_DATE="2026-01-06T00:00:00Z" git commit -a -m 'w'

git checkout main
git merge wip --no-edit

Expected

No Errors. A.rs is created and last modified in 2025. B.rs is created and last modified in 2026.

Actual

hawkeye format wants to update both files to 2025 - 2026.

Details

The repro above has the following history:

main: init - base - mA2025 - mB2026 --- dummy - random - merge
wip:            +------------------- w ------------------+

The current traversal order is:

merge - random - w - dummy - base - mB2026 - init - mA2025
  • When next_commit = base and this_commit = mB2026, the worktree diff would contain deletion of B.rs at commit time of base, leading to wrong created time of B.rs being 2025.
  • When next_commit = random and this_commit = w, the worktree diff would contain addition of A.rs at commit time of random, leading to wrong updated time of A.rs being 2026.

Potential workarounds/solutions

  • Give up on supporting merge-commit and clearly require linear history in README.
    • Especially, users of actions/checkout need to configure ref to HEAD rather than defaulting to merge commit.
  • Pass Sorting::ByCommitTime to gix instead of the default BreadthFirst. This can fix created but modified is still wrong.
  • Avoid relying on traversal order and worktree diff. Find other ways to identify file changes inside a commit.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions