Commit Diff


commit - 1ad7903cd8c5410dc6573ea27d284a4fa79ec184
commit + 2c9cf9de8266aee2b966fb1f89eb6c55fbcc7a23
blob - 43ced4d67ba8e0cf0069e523d5112f6b9d8e6d77
blob + 13b839d893f897375de0e9464be3c3b29dadffc0
--- NEWS
+++ NEWS
@@ -4,6 +4,9 @@
 
  * Fix fetching into MemoryRepo. (Jelmer Vernooij, #1157)
 
+ * Support ``init.defaultBranch`` config.
+   (Jelmer Vernooij)
+
 0.21.3	2023-02-17
 
  * Add support for ``worktreeconfig`` extension.
blob - 95e5d1718f15aad4e0d34e272fd7a4eec94a926f
blob + 3435dcdb20838dfe9a2a44f51691c33357fe5588
--- dulwich/objectspec.py
+++ dulwich/objectspec.py
@@ -20,16 +20,21 @@
 
 """Object specification."""
 
-from typing import List, Tuple, Union
+from typing import List, Tuple, Union, TYPE_CHECKING, Optional, Iterator
 
+if TYPE_CHECKING:
+    from dulwich.objects import ShaFile, Commit, Tree
+    from dulwich.refs import RefsContainer, Ref
+    from dulwich.repo import Repo
 
-def to_bytes(text):
+
+def to_bytes(text: Union[str, bytes]) -> bytes:
     if getattr(text, "encode", None) is not None:
-        text = text.encode("ascii")
-    return text
+        text = text.encode("ascii")  # type: ignore
+    return text  # type: ignore
 
 
-def parse_object(repo, objectish):
+def parse_object(repo: "Repo", objectish: Union[bytes, str]) -> "ShaFile":
     """Parse a string referring to an object.
 
     Args:
@@ -43,7 +48,7 @@ def parse_object(repo, objectish):
     return repo[objectish]
 
 
-def parse_tree(repo, treeish):
+def parse_tree(repo: "Repo", treeish: Union[bytes, str]) -> "Tree":
     """Parse a string referring to a tree.
 
     Args:
@@ -64,7 +69,7 @@ def parse_tree(repo, treeish):
     return o
 
 
-def parse_ref(container, refspec):
+def parse_ref(container: Union["Repo", "RefsContainer"], refspec: Union[str, bytes]) -> "Ref":
     """Parse a string referring to a reference.
 
     Args:
@@ -89,7 +94,10 @@ def parse_ref(container, refspec):
     raise KeyError(refspec)
 
 
-def parse_reftuple(lh_container, rh_container, refspec, force=False):
+def parse_reftuple(
+        lh_container: Union["Repo", "RefsContainer"],
+        rh_container: Union["Repo", "RefsContainer"], refspec: Union[str, bytes],
+        force: bool = False) -> Tuple[Optional["Ref"], Optional["Ref"], bool]:
     """Parse a reftuple spec.
 
     Args:
@@ -104,6 +112,8 @@ def parse_reftuple(lh_container, rh_container, refspec
     if refspec.startswith(b"+"):
         force = True
         refspec = refspec[1:]
+    lh: Optional[bytes]
+    rh: Optional[bytes]
     if b":" in refspec:
         (lh, rh) = refspec.split(b":")
     else:
@@ -125,8 +135,9 @@ def parse_reftuple(lh_container, rh_container, refspec
 
 
 def parse_reftuples(
-        lh_container, rh_container,
-        refspecs: Union[bytes, List[bytes], List[Tuple[bytes, bytes]]],
+        lh_container: Union["Repo", "RefsContainer"],
+        rh_container: Union["Repo", "RefsContainer"],
+        refspecs: Union[bytes, List[bytes]],
         force: bool = False):
     """Parse a list of reftuple specs to a list of reftuples.
 
@@ -167,7 +178,7 @@ def parse_refs(container, refspecs):
     return ret
 
 
-def parse_commit_range(repo, committishs):
+def parse_commit_range(repo: "Repo", committishs: Union[str, bytes]) -> Iterator["Commit"]:
     """Parse a string referring to a range of commits.
 
     Args:
@@ -206,7 +217,7 @@ def scan_for_short_id(object_store, prefix):
     raise AmbiguousShortId(prefix, ret)
 
 
-def parse_commit(repo, committish):
+def parse_commit(repo: "Repo", committish: Union[str, bytes]) -> "Commit":
     """Parse a string referring to a single commit.
 
     Args:
blob - a0839bdb675fbf5e928aa5ed3675169d4631af0c
blob + f16c847baa1bffa22e2dbad42380c885e3745525
--- dulwich/repo.py
+++ dulwich/repo.py
@@ -85,7 +85,7 @@ BASE_DIRECTORIES = [
     ["info"],
 ]
 
-DEFAULT_REF = b"refs/heads/master"
+DEFAULT_BRANCH = b"master"
 
 
 class InvalidUserIdentity(Exception):
@@ -1590,18 +1590,28 @@ class Repo(BaseRepo):
         self._put_named_file("description", description)
 
     @classmethod
-    def _init_maybe_bare(cls, path, controldir, bare, object_store=None):
+    def _init_maybe_bare(
+            cls, path, controldir, bare, object_store=None, config=None,
+            default_branch=None):
         for d in BASE_DIRECTORIES:
             os.mkdir(os.path.join(controldir, *d))
         if object_store is None:
             object_store = DiskObjectStore.init(os.path.join(controldir, OBJECTDIR))
         ret = cls(path, bare=bare, object_store=object_store)
-        ret.refs.set_symbolic_ref(b"HEAD", DEFAULT_REF)
+        if default_branch is None:
+            if config is None:
+                from dulwich.config import StackedConfig
+                config = StackedConfig.default()
+            try:
+                default_branch = config.get("init", "defaultBranch")
+            except KeyError:
+                default_branch = DEFAULT_BRANCH
+        ret.refs.set_symbolic_ref(b"HEAD", LOCAL_BRANCH_PREFIX + default_branch)
         ret._init_files(bare)
         return ret
 
     @classmethod
-    def init(cls, path: str, mkdir: bool = False) -> "Repo":
+    def init(cls, path: str, *, mkdir: bool = False, config=None, default_branch=None) -> "Repo":
         """Create a new repository.
 
         Args:
@@ -1614,7 +1624,9 @@ class Repo(BaseRepo):
         controldir = os.path.join(path, CONTROLDIR)
         os.mkdir(controldir)
         _set_filesystem_hidden(controldir)
-        return cls._init_maybe_bare(path, controldir, False)
+        return cls._init_maybe_bare(
+            path, controldir, False, config=config,
+            default_branch=default_branch)
 
     @classmethod
     def _init_new_working_directory(cls, path, main_repo, identifier=None, mkdir=False):
@@ -1655,7 +1667,7 @@ class Repo(BaseRepo):
         return r
 
     @classmethod
-    def init_bare(cls, path, mkdir=False, object_store=None):
+    def init_bare(cls, path, *, mkdir=False, object_store=None, config=None, default_branch=None):
         """Create a new bare repository.
 
         ``path`` should already exist and be an empty directory.
@@ -1666,7 +1678,7 @@ class Repo(BaseRepo):
         """
         if mkdir:
             os.mkdir(path)
-        return cls._init_maybe_bare(path, path, True, object_store=object_store)
+        return cls._init_maybe_bare(path, path, True, object_store=object_store, config=config, default_branch=default_branch)
 
     create = init_bare
 
blob - 6a9bbcf54b7d834597c5bda5a22f1446566cfb2c
blob + c3f3a9d30ee15719a3dc3f242d33840bebd9727e
--- dulwich/tests/__init__.py
+++ dulwich/tests/__init__.py
@@ -170,15 +170,33 @@ def tutorial_test_suite():
     ]
     tutorial_files = [f"../../docs/tutorial/{name}.txt" for name in tutorial]
 
+    to_restore = []
+
+    def overrideEnv(name, value):
+        oldval = os.environ.get(name)
+        if value is not None:
+            os.environ[name] = value
+        else:
+            del os.environ[name]
+        to_restore.append((name, oldval))
+
     def setup(test):
         test.__old_cwd = os.getcwd()
         test.tempdir = tempfile.mkdtemp()
         test.globs.update({"tempdir": test.tempdir})
         os.chdir(test.tempdir)
+        overrideEnv("HOME", "/nonexistent")
+        overrideEnv("GIT_CONFIG_NOSYSTEM", "1")
 
     def teardown(test):
         os.chdir(test.__old_cwd)
         shutil.rmtree(test.tempdir)
+        for name, oldval in to_restore:
+            if oldval is not None:
+                os.environ[name] = oldval
+            else:
+                del os.environ[name]
+        to_restore.clear()
 
     return doctest.DocFileSuite(
         module_relative=True,