From 88a7e88e54d27f8d6068ba3d86fe61c291ab76a5 Mon Sep 17 00:00:00 2001 From: Gavin Mak Date: Mon, 22 Jun 2026 22:36:20 +0000 Subject: [PATCH] info: Report actual checked-out HEAD revision When `repo info` runs, the reported "Current revision" is resolved using the manifest's target branch tracking ref (e.g. refs/remotes/goog/main). Introduce Project.GetHeadRevisionId(), which gets the checked-out HEAD commit in the worktree, and use it in `repo info` with a fallback to the old behavior if the project is not checked out. Bug: 526685287 Change-Id: I72280ce27daa210cada27d722a94e365644f06e0 Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/599481 Reviewed-by: Brian Gan Commit-Queue: Gavin Mak Tested-by: Gavin Mak --- project.py | 12 ++++++++++++ subcmds/info.py | 5 +++-- tests/test_project.py | 22 ++++++++++++++++++++++ tests/test_subcmds_info.py | 24 ++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/project.py b/project.py index 0b336b272..06719401b 100644 --- a/project.py +++ b/project.py @@ -1647,6 +1647,18 @@ class Project: f"revision {self.revisionExpr} in {self.name} not found" ) + def GetHeadRevisionId(self) -> Optional[str]: + """Get the commit revision of the checked out HEAD. + + Returns None if worktree is not checked out or HEAD cannot be resolved. + """ + if self.work_git: + try: + return self.work_git.rev_parse("HEAD") + except GitError: + pass + return None + def GetRevisionId(self, all_refs=None): if self.revisionId: return self.revisionId diff --git a/subcmds/info.py b/subcmds/info.py index 19bb36d2a..a089838a4 100644 --- a/subcmds/info.py +++ b/subcmds/info.py @@ -196,7 +196,8 @@ class Info(PagedCommand): data = { "name": project.name, "mount_path": project.worktree, - "current_revision": project.GetRevisionId(), + "current_revision": project.GetHeadRevisionId() + or project.GetRevisionId(), "manifest_revision": project.revisionExpr, "local_branches": list(project.GetBranches()), } @@ -273,7 +274,7 @@ class Info(PagedCommand): out.nl() heading("Current revision: ") - headtext(project.GetRevisionId()) + headtext(project.GetHeadRevisionId() or project.GetRevisionId()) out.nl() currentBranch = project.CurrentBranch diff --git a/tests/test_project.py b/tests/test_project.py index a824407cf..3973bcfec 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -104,6 +104,28 @@ class ProjectTests(unittest.TestCase): "abcd00%21%21_%2b", ) + def test_get_head_revision_id(self): + """Check GetHeadRevisionId behavior.""" + with utils_for_test.TempGitTree() as tempdir: + proj = _create_mock_project(tempdir) + + # Initially unborn HEAD should return None. + self.assertIsNone(proj.GetHeadRevisionId()) + + # Create a commit. + with open(os.path.join(tempdir, "readme"), "w") as fp: + fp.write("hello") + proj.work_git.add("readme") + proj.work_git.commit("-m", "initial commit") + + # HEAD should resolve to the commit SHA. + commit_sha = proj.work_git.rev_parse("HEAD") + self.assertEqual(commit_sha, proj.GetHeadRevisionId()) + + # Even if worktree is detached. + proj.work_git.checkout("HEAD~0") + self.assertEqual(commit_sha, proj.GetHeadRevisionId()) + @unittest.skipUnless( utils_for_test.supports_reftable(), "git reftable support is required for this test", diff --git a/tests/test_subcmds_info.py b/tests/test_subcmds_info.py index 788ea9e26..dd6065339 100644 --- a/tests/test_subcmds_info.py +++ b/tests/test_subcmds_info.py @@ -199,3 +199,27 @@ def test_text_enables_pager() -> None: cmd = _get_cmd() opts, _ = cmd.OptionParser.parse_args([]) assert cmd.WantPager(opts) + + +def test_get_project_data_uses_head_revision() -> None: + """_getProjectData should use GetHeadRevisionId if available.""" + cmd = _get_cmd() + project = mock.MagicMock() + project.name = "foo" + project.worktree = "/path/to/foo" + project.revisionExpr = "refs/heads/main" + project.GetBranches.return_value = [] + + # GetHeadRevisionId() returns a SHA, it should be used. + project.GetHeadRevisionId.return_value = "head_sha_12345" + project.GetRevisionId.return_value = "manifest_sha_54321" + + data = cmd._getProjectData(project) + assert data["current_revision"] == "head_sha_12345" + project.GetHeadRevisionId.assert_called_once() + + # GetHeadRevisionId() is None, fall back to GetRevisionId(). + project.GetHeadRevisionId.reset_mock() + project.GetHeadRevisionId.return_value = None + data = cmd._getProjectData(project) + assert data["current_revision"] == "manifest_sha_54321"