changeset 6:7113e0ac3662

fix refs on git-export; clean up how gitserve export works.
author Paul Fisher <paul@pfish.zone>
date Sun, 15 Feb 2026 01:31:53 -0500
parents c43ce246240b
children 4f42fdbb25f2
files src/git_serve/__init__.py
diffstat 1 files changed, 59 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/src/git_serve/__init__.py	Sat Feb 14 21:39:54 2026 -0500
+++ b/src/git_serve/__init__.py	Sun Feb 15 01:31:53 2026 -0500
@@ -141,7 +141,7 @@
         refs.remove_if_equals(ref, None)
 
 
-def _set_head(repo: GittyRepo) -> None:
+def _set_head(ui: hgui.ui, repo: GittyRepo, at_name: bytes) -> None:
     """Creates a HEAD reference in Git referring to the current HEAD."""
     # By default, we use '@', since that's what will be auto checked out.
     current = b'@'
@@ -152,76 +152,92 @@
     git_current = current
     if current == b'@':
         # @ is a special keyword in Git, so we can't use it as a bookmark.
-        git_current = b'__default__'
+        git_current = at_name
     git_branch = dulwich.refs.LOCAL_BRANCH_PREFIX + git_current
     if not dulwich.refs.check_ref_format(git_branch):
         # We can't export this ref to Git. Give up.
+        ui.warn(f'{git_branch!r} is not a valid branch name for Git.'.encode())
+        return
+    try:
+        # Maybe this is a real bookmark?
+        hgsha = repo._bookmarks[current]
+    except KeyError:
+        # Not a real bookmark. Assume we want the tip of the current branch.
+        branch = repo.dirstate.branch()
+        try:
+            tip = repo.branchtip(branch)
+        except hgerr.RepoLookupError:
+            # This branch somehow doesn't exist???
+            ui.warn(f"{branch} doesn't seem to exist?".encode())
+            return
+        hgsha = binascii.hexlify(tip)
+    gitsha = repo.githandler.map_git_get(hgsha)
+    if not gitsha:
+        # No Git SHA to match this Hg sha. Give up.
+        ui.warn(f'revision {hgsha} was not exported to Git'.encode())
         return
     refs = repo.githandler.git.refs
-    if git_branch not in refs:
-        # This means our bookmark isn't actually in Git (usually because
-        # there's no real bookmark called '@'). We need to fake it.
-        try:
-            # Maybe this is a real bookmark?
-            hgsha = repo._bookmarks[current]
-        except KeyError:
-            # Not a real bookmark. Assume we want the tip of the current branch.
-            branch = repo.dirstate.branch()
-            try:
-                tip = repo.branchtip(branch)
-            except hgerr.RepoLookupError:
-                # This branch somehow doesn't exist???
-                return
-            hgsha = binascii.hexlify(tip)
-        gitsha = repo.githandler.map_git_get(hgsha)
-        if not gitsha:
-            # No Git SHA to match this Hg sha. Give up.
-            return
-        refs.add_packed_refs({git_branch: gitsha})
+    refs.add_packed_refs({git_branch: gitsha})
     refs.set_symbolic_ref(b'HEAD', git_branch)
 
 
-def _export_hook(ui: hgui.ui, repo: GittyRepo, **__: object) -> None:
+def fix_refs_hook(ui: hgui.ui, repo: hgrepo.IRepo, **__: object) -> None:
     """Exports to Git and sets up for serving."""
-    never_export = ui.configbool(b'git-serve', b'never-export')
-    if never_export:
+    if not _is_gitty(repo):
         return
-    always_export = ui.configbool(b'git-serve', b'always-export', False)
-    if always_export or os.path.isdir(repo.githandler.gitdir):
-        _export_repo(repo)
+    _fix_refs(ui, repo)
 
 
-def _export_repo(repo: GittyRepo) -> None:
-    """Do the actual exporting."""
+def _fix_refs(ui: hgui.ui, repo: GittyRepo) -> None:
+    """After a git export, fix up the refs."""
     _clean_all_refs(repo.githandler.git.refs)
-    repo.githandler.export_commits()
-    _set_head(repo)
+    repo.githandler.export_hg_tags()
+    repo.githandler.update_references()
+    default_branch_name = ui.config(
+        b'hggit-serve', b'default-branch', b'default'
+    )
+    _set_head(ui, repo, default_branch_name)
+
+
+def export_hook(ui: hgui.ui, repo: hgrepo.IRepo, **__: object) -> None:
+    if not _is_gitty(repo):
+        return
+    auto_export = ui.config(b'hggit-serve', b'auto-export')
+    if auto_export == b'never':
+        return
+    if auto_export == b'always' or os.path.isdir(repo.githandler.gitdir):
+        repo.githandler.export_commits()
+        _fix_refs(ui, repo)
 
 
 # Interfacing with Mercurial
 
-__version__ = '0.1.3'
+__version__ = '0.1.4'
+testedwith = b'7.1 7.2'
 
 cmdtable: dict[bytes, object] = {}
 
 command = registrar.command(cmdtable)
 
 
-@command(b'git-serve-export')
-def git_serve_export(_: hgui.ui, repo: hgrepo.IRepo, **__: object) -> None:
-    if not _is_gitty(repo):
-        raise hgerr.Abort(b'this extension depends on the `hggit` extension')
-    _export_repo(repo)
-
-
 def uisetup(_: hgui.ui) -> None:
     extensions.wrapfunction(
         wireprotoserver, 'handlewsgirequest', _handle_git_protocol
     )
 
 
-def reposetup(ui: hgui.ui, _: hgrepo.IRepo) -> None:
-    ui.setconfig(b'hooks', b'txnclose.__gitserve_internal__', _export_hook)
+def uipopulate(ui: hgui.ui) -> None:
+    ui.setconfig(
+        b'hooks', b'post-git-export.__gitserve_add_tag__', fix_refs_hook
+    )
+    ui.setconfig(b'hooks', b'txnclose.__gitserve_export__', export_hook)
 
 
-__all__ = ('__version__', 'cmdtable', 'command', 'uisetup', 'reposetup')
+__all__ = (
+    '__version__',
+    'cmdtable',
+    'command',
+    'testedwith',
+    'uipopulate',
+    'uisetup',
+)