dirstate: write the `branch` as part of the transaction if any
authorPierre-Yves David <pierre-yves.david@octobus.net>
Thu, 02 Mar 2023 11:47:18 +0100
changeset 50256 a6e0b7d4ae9d
parent 50255 fa04407bda7a
child 50257 a301f0fad046
dirstate: write the `branch` as part of the transaction if any Bypassing the transaction means we could get out of sync with the dirstatemap content. The branch is stil written right away if no transaction is around, but at least it no longer bypass the transaction. Actual caller of this still need to be updated.
hgext/git/dirstate.py
mercurial/dirstate.py
mercurial/interfaces/dirstate.py
--- a/hgext/git/dirstate.py	Thu Mar 02 11:46:51 2023 +0100
+++ b/hgext/git/dirstate.py	Thu Mar 02 11:47:18 2023 +0100
@@ -389,7 +389,7 @@
         # TODO: should this be added to the dirstate interface?
         self._plchangecallbacks[category] = callback
 
-    def setbranch(self, branch):
+    def setbranch(self, branch, transaction=None):
         raise error.Abort(
             b'git repos do not support branches. try using bookmarks'
         )
--- a/mercurial/dirstate.py	Thu Mar 02 11:46:51 2023 +0100
+++ b/mercurial/dirstate.py	Thu Mar 02 11:47:18 2023 +0100
@@ -27,6 +27,7 @@
     policy,
     pycompat,
     scmutil,
+    txnutil,
     util,
 )
 
@@ -416,10 +417,19 @@
 
     @repocache(b'branch')
     def _branch(self):
+        f = None
+        data = b''
         try:
-            return self._opener.read(b"branch").strip() or b"default"
+            f, mode = txnutil.trypending(self._root, self._opener, b'branch')
+            data = f.read().strip()
         except FileNotFoundError:
+            pass
+        finally:
+            if f is not None:
+                f.close()
+        if not data:
             return b"default"
+        return data
 
     @property
     def _pl(self):
@@ -611,11 +621,22 @@
         fold_p2 = oldp2 != nullid and p2 == nullid
         return self._map.setparents(p1, p2, fold_p2=fold_p2)
 
-    def setbranch(self, branch):
+    def setbranch(self, branch, transaction=None):
         self.__class__._branch.set(self, encoding.fromlocal(branch))
+        if transaction is not None:
+            self._setup_tr_abort(transaction)
+            transaction.addfilegenerator(
+                b'dirstate-3-branch%s' % self._tr_key_suffix,
+                (b'branch',),
+                self._write_branch,
+                location=b'plain',
+                post_finalize=True,
+            )
+            return
+
         vfs = self._opener
         with vfs(b'branch', b'w', atomictemp=True, checkambig=True) as f:
-            f.write(self._branch + b'\n')
+            self._write_branch(f)
             # make sure filecache has the correct stat info for _branch after
             # replacing the underlying file
             #
@@ -625,6 +646,9 @@
             if ce:
                 ce.refresh()
 
+    def _write_branch(self, file_obj):
+        file_obj.write(self._branch + b'\n')
+
     def invalidate(self):
         """Causes the next access to reread the dirstate.
 
--- a/mercurial/interfaces/dirstate.py	Thu Mar 02 11:46:51 2023 +0100
+++ b/mercurial/interfaces/dirstate.py	Thu Mar 02 11:47:18 2023 +0100
@@ -123,7 +123,7 @@
         See localrepo.setparents()
         """
 
-    def setbranch(branch):
+    def setbranch(branch, transaction=None):
         pass
 
     def invalidate():