Skip to content

Commit 117f6e7

Browse files
jbbqqfclaude
andcommitted
metrics: handle distinct refs resolving to the same SHA in diff (#10429)
`dvc metrics diff --all <a> <b>` returned `{}` when `a` and `b` were distinct ref names that pointed at the same commit (e.g. `main` and `HEAD`). The brancher groups same-SHA revisions under a single comma-joined composite key (e.g. `"main,HEAD"`), but `_diff()` looked each rev up by exact key, missed the composite, and produced an empty result instead of an all-zero diff. Fall back to membership lookup when the direct key isn't present. This also implicitly fixes `dvc params diff --all <a> <b>`, which delegates to the same `_diff` helper. Co-Authored-By: Claude Code <noreply@anthropic.com>
1 parent 06ff81c commit 117f6e7

2 files changed

Lines changed: 37 additions & 2 deletions

File tree

dvc/repo/metrics/diff.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,29 @@ class DiffResult(TypedDict, total=False):
1616
diff: dict[str, dict[str, dict]]
1717

1818

19+
def _resolve_rev(result: dict[str, "Result"], rev: str) -> "Result":
20+
# Direct hit when brancher emitted this rev as its own key.
21+
if rev in result:
22+
return result[rev]
23+
# Brancher groups revisions resolving to the same SHA under a single
24+
# comma-joined composite key (e.g. "main,HEAD" when both resolve to the
25+
# same commit). Fall back to lookup by membership so callers passing two
26+
# distinct ref names that happen to point at the same commit still get a
27+
# result. See https://github.com/iterative/dvc/issues/10429.
28+
for key, value in result.items():
29+
if rev in key.split(","):
30+
return value
31+
return {}
32+
33+
1934
def _diff(
2035
result: dict[str, "Result"],
2136
old_rev: str,
2237
new_rev: str,
2338
**kwargs,
2439
) -> DiffResult:
25-
old = result.get(old_rev, {})
26-
new = result.get(new_rev, {})
40+
old = _resolve_rev(result, old_rev)
41+
new = _resolve_rev(result, new_rev)
2742

2843
old_data = old.get("data", {})
2944
new_data = new.get("data", {})

tests/func/metrics/test_diff.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@
99
from dvc.utils.serialize import JSONFileCorruptedError
1010

1111

12+
def test_metrics_diff_same_commit_different_refs(tmp_dir, scm, dvc, run_copy_metrics):
13+
# Regression for https://github.com/iterative/dvc/issues/10429.
14+
# When a_rev and b_rev are distinct ref names that happen to resolve to the
15+
# same SHA (e.g. "main" and "HEAD"), brancher groups them under a single
16+
# composite key like "main,HEAD" in the metrics.show() result. The old
17+
# _diff() looked up "main" and "HEAD" individually and returned {}; the
18+
# expected behavior is an all-zero diff (same metrics on both sides).
19+
tmp_dir.gen({"m_temp.yaml": "1"})
20+
run_copy_metrics("m_temp.yaml", "m.yaml", name="copy-metrics", metrics=["m.yaml"])
21+
dvc.scm.commit("add metrics")
22+
23+
branch_name = scm.active_branch()
24+
expected = {"m.yaml": {"": {"old": 1, "new": 1, "diff": 0}}}
25+
26+
# both ref names resolve to the same SHA -> diff should still report all-zero
27+
assert dvc.metrics.diff(a_rev=branch_name, b_rev="HEAD", all=True) == {
28+
"diff": expected
29+
}
30+
31+
1232
def test_metrics_diff_simple(tmp_dir, scm, dvc, run_copy_metrics):
1333
def _gen(val):
1434
tmp_dir.gen({"m_temp.yaml": str(val)})

0 commit comments

Comments
 (0)