"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Mark Jamsek <mark@jamsek.com>
Subject:
got: gotadmin init and got import -b coherence
To:
Game of Trees <gameoftrees@openbsd.org>
Date:
Sun, 21 Aug 2022 00:01:33 +1000

Download raw body.

Thread
I introduced some Fossilers to Got today and came across this issue.

In Fossil, the default branch is "trunk", so for familiarity I thought
I'd use the -b option to `got import` to make the initial commit on
"trunk" and thus expected HEAD to reference "trunk":

  $ gotadmin init new.git
  $ got import -r new.git -b trunk -m "initial commit" ~/src/tmp
  A  /home/mark/src/tmp/runnit.c
  Created branch refs/heads/trunk with commit 85e40007698d1e988e97d8c8f94171f77b2a8579
  $ got co new.git
  got: reference refs/heads/main not found
  $ got co -b trunk new.git
  A  /home/mark/src/new/runnit.c
  Checked out refs/heads/trunk: 85e40007698d1e988e97d8c8f94171f77b2a8579
  Now shut up and hack
  $ cd new && tog
  tog: reference refs/heads/main not found
  $ got log
  got: reference refs/heads/main not found
  $ got log -c trunk
  got: reference refs/heads/main not found

As a new repository, I incorrectly assumed that `got import -b trunk`
would make HEAD point to "trunk". However, HEAD is still "main", which
doesn't exist.

I just had a quick look and made this patch to check if we create new
repositories with a "trunk" HEAD if anything noticeable breaks.

  $ gotadmin init -b trunk new.git
  $ got import -r new.git -b trunk -m "initial commit" ~/src/tmp
  A  /home/mark/src/tmp/runnit.c
  Created branch refs/heads/trunk with commit bafecf8a578c2a1d80dcfdc81084840453d30007
  $ got co new.git
  A  /home/mark/src/new/runnit.c
  Checked out refs/heads/trunk: bafecf8a578c2a1d80dcfdc81084840453d30007
  Now shut up and hack
  $ cd new && got log
  -----------------------------------------------
  commit bafecf8a578c2a1d80dcfdc81084840453d30007 (trunk)
  from: Mark Jamsek <mark@jamsek.dev>
  date: Sat Aug 20 13:47:28 2022 UTC

   initial commit

So far so good, but I have a few questions:

  - have I missed something and there's already a way to do this?
  - assuming I haven't, do we just want users to manually edit
    repo.git/HEAD if they want a new repo with something other than
    "main"?
  - if not, are we open to something like this (or something else
    entirely) so users can make HEAD reference <branch-other-than-main>
    when creating new repositories?
  - if yes, I'm not sure I like making the user have to use -b with
    `gotadmin init` and then again with `got import`; would it be better
    to either read or write HEAD during import so the user only needs to
    use -b once (either with `gotadmin init -b` or `got import -b`) to
    have HEAD point to something other than "main"? OTOH, it's at least
    consistent and easy to remember using -b for both init and import,
    and the change is minimal

diff refs/heads/main refs/heads/dev/gotadmin
commit - 026ac2c462910064c5c9143a96b17a920e6bbc58
commit + 8bb9f49eecff4b8726dd1c5106c73be2d2c6f809
blob - d629445e1b234fb60ebb1aa76195a8d2283e029a
blob + 9ac4cf70ccec9e2b1921968caa1c627d5d682d86
--- got/got.1
+++ got/got.1
@@ -102,7 +102,12 @@ instead of creating the default branch
 .Dq main .
 Use of this option is required if the
 .Dq main
-branch already exists.
+branch already exists, or if the
+.Fl b
+option was used to specify a branch other than
+.Dq main
+as the repository's HEAD reference when creating the repository with
+.Cm gotadmin init .
 .It Fl I Ar pattern
 Ignore files or directories with a name which matches the specified
 .Ar pattern .
blob - f9bcb1bca8436bc052e3bdeab3be53a13add0a61
blob + ee8fd1138f21031552a0957b443e5c0c66b2eb9f
--- got/got.c
+++ got/got.c
@@ -1689,7 +1689,7 @@ cmd_clone(int argc, char *argv[])
 		goto done;
 
 	if (!list_refs_only) {
-		error = got_repo_init(repo_path);
+		error = got_repo_init(repo_path, NULL);
 		if (error)
 			goto done;
 		error = got_repo_pack_fds_open(&pack_fds);
blob - 0f970bf8e42b6329fb4b1718ff50f3d637eb442f
blob + 521816ab92f9c7d69e823c06dd5b547a1381eeb9
--- gotadmin/gotadmin.1
+++ gotadmin/gotadmin.1
@@ -53,7 +53,7 @@ The commands for
 .Nm
 are as follows:
 .Bl -tag -width checkout
-.It Cm init Ar repository-path
+.It Cm init Oo Fl b Ar branch Oc Ar repository-path
 Create a new empty repository at the specified
 .Ar repository-path .
 .Pp
@@ -64,6 +64,17 @@ the
 command must be used to populate the empty repository before
 .Cm got checkout
 can be used.
+.Pp
+The options for
+.Cm gotadmin init
+are as follows:
+.Bl -tag -width Ds
+.It Fl b Ar branch
+Make the specified
+.Ar branch
+resolve to the repository's HEAD reference instead of the default branch
+.Dq main .
+.El
 .It Cm info Oo Fl r Ar repository-path Oc
 Display information about a repository.
 This includes some configuration settings from
blob - cc47823cd2100f2565e4172a84472e2fb5ffd7bd
blob + 3d80a49a286807837e83114ca3528a1bf989113d
--- gotadmin/gotadmin.c
+++ gotadmin/gotadmin.c
@@ -279,11 +279,15 @@ static const struct got_error *
 cmd_init(int argc, char *argv[])
 {
 	const struct got_error *error = NULL;
+	const char *head_name = NULL;
 	char *repo_path = NULL;
 	int ch;
 
-	while ((ch = getopt(argc, argv, "")) != -1) {
+	while ((ch = getopt(argc, argv, "b:")) != -1) {
 		switch (ch) {
+		case 'b':
+			head_name = optarg;
+			break;
 		default:
 			usage_init();
 			/* NOTREACHED */
@@ -315,7 +319,7 @@ cmd_init(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_repo_init(repo_path);
+	error = got_repo_init(repo_path, head_name);
 done:
 	free(repo_path);
 	return error;
blob - dea6dd81d267dfa92571a33f5c7559726bab8d8b
blob + 4f8b24e0e19f1af4e21707388cf9bbf9bb54cd18
--- include/got_repository.h
+++ include/got_repository.h
@@ -130,8 +130,11 @@ int got_repo_is_bare(struct got_repository *);
 const struct got_error *got_repo_map_path(char **, struct got_repository *,
     const char *);
 
-/* Create a new repository in an empty directory at a specified path. */
-const struct got_error *got_repo_init(const char *);
+/*
+ * Create a new repository with optional specified
+ * HEAD ref in an empty directory at a specified path.
+ */
+const struct got_error *got_repo_init(const char *, const char *);
 
 /* Attempt to find a unique object ID for a given ID string prefix. */
 const struct got_error *got_repo_match_object_id_prefix(struct got_object_id **,
blob - a47b26a8fcc75a0889cc09cd5b7230842ec0ae6e
blob + ca38bdf3f2d2c88d5eadccd7572dc438ee6b667a
--- lib/repository.c
+++ lib/repository.c
@@ -1552,7 +1552,7 @@ got_repo_unpin_pack(struct got_repository *repo)
 }
 
 const struct got_error *
-got_repo_init(const char *repo_path)
+got_repo_init(const char *repo_path, const char *head_name)
 {
 	const struct got_error *err = NULL;
 	const char *dirnames[] = {
@@ -1562,12 +1562,12 @@ got_repo_init(const char *repo_path)
 	};
 	const char *description_str = "Unnamed repository; "
 	    "edit this file 'description' to name the repository.";
-	const char *headref_str = "ref: refs/heads/main";
+	const char *headref = "ref: refs/heads/";
 	const char *gitconfig_str = "[core]\n"
 	    "\trepositoryformatversion = 0\n"
 	    "\tfilemode = true\n"
 	    "\tbare = true\n";
-	char *path;
+	char *headref_str, *path;
 	size_t i;
 
 	if (!got_path_dir_is_empty(repo_path))
@@ -1592,7 +1592,13 @@ got_repo_init(const char *repo_path)
 
 	if (asprintf(&path, "%s/%s", repo_path, GOT_HEAD_FILE) == -1)
 		return got_error_from_errno("asprintf");
+	if (asprintf(&headref_str, "%s%s", headref,
+	    head_name ? head_name : "main") == -1) {
+		free(path);
+		return got_error_from_errno("asprintf");
+	}
 	err = got_path_create_file(path, headref_str);
+	free(headref_str);
 	free(path);
 	if (err)
 		return err;

-- 
Mark Jamsek <fnc.bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80  E6E2 2930 DC66 86EE CF68