Commit a4f89d488d527ac3e4234f22eca2ce92d5ab46a7

Stefan Sperling 2019-08-25T13:45:30

allow creating branches based on commit IDs as well as other branch references

diff --git a/got/got.1 b/got/got.1
index ffc4d07..977bfb4 100644
--- a/got/got.1
+++ b/got/got.1
@@ -475,7 +475,7 @@ which must be an existing reference.
 Care should be taken not to create loops between references when
 this option is used.
 .El
-.It Cm branch Oo Fl r Ar repository-path Oc Oo Fl l Oc Oo Fl d Ar name Oc Op Ar name Op Ar base-branch
+.It Cm branch Oo Fl r Ar repository-path Oc Oo Fl l Oc Oo Fl d Ar name Oc Op Ar name Op Ar commit
 Manage branches in a repository.
 .Pp
 Branches are managed via references which live in the
@@ -486,14 +486,19 @@ The
 command operates on references in this namespace only.
 .Pp
 If no options are passed, expect one or two arguments and attempt to create
-a branch with the given
+a branch reference with the given
 .Ar name ,
 and make it point at the given
-.Ar base-branch .
+.Ar commit .
+The expected
+.Ar commit
+argument is a commit ID SHA1 hash or an existing reference
+or tag name which will be resolved to a commit ID.
 If no
-.Ar base-branch
-is specified, default to the work tree's current branch if invoked in a
-work tree, or to the repository's HEAD reference.
+.Ar commit
+is specified, default to the latest commit on the work tree's current
+branch if invoked in a work tree, or to a commit resolved via the
+repository's HEAD reference.
 .Pp
 The options for
 .Cm got branch
diff --git a/got/got.c b/got/got.c
index 7daf89c..c5f0c6c 100644
--- a/got/got.c
+++ b/got/got.c
@@ -3056,7 +3056,7 @@ usage_branch(void)
 {
 	fprintf(stderr,
 	    "usage: %s branch [-r repository] -l | -d name | "
-	    "name [base-branch]\n", getprogname());
+	    "name [commit]\n", getprogname());
 	exit(1);
 }
 
@@ -3140,9 +3140,9 @@ add_branch(struct got_repository *repo, const char *branch_name,
 {
 	const struct got_error *err = NULL;
 	struct got_object_id *id = NULL;
+	char *label;
 	struct got_reference *ref = NULL;
 	char *base_refname = NULL, *refname = NULL;
-	struct got_reference *base_ref;
 
 	/*
 	 * Don't let the user create a branch named '-'.
@@ -3152,20 +3152,10 @@ add_branch(struct got_repository *repo, const char *branch_name,
 	if (branch_name[0] == '-' && branch_name[1] == '\0')
 		return got_error(GOT_ERR_BAD_REF_NAME);
 
-	if (strcmp(GOT_REF_HEAD, base_branch) == 0) {
-		base_refname = strdup(GOT_REF_HEAD);
-		if (base_refname == NULL)
-			return got_error_from_errno("strdup");
-	} else if (asprintf(&base_refname, "refs/heads/%s", base_branch) == -1)
-		return got_error_from_errno("asprintf");
-
-	err = got_ref_open(&base_ref, repo, base_refname, 0);
-	if (err)
-		goto done;
-	err = got_ref_resolve(&id, repo, base_ref);
-	got_ref_close(base_ref);
+	err = match_object_id(&id, &label, base_branch,
+	    GOT_OBJ_TYPE_COMMIT, 1, repo);
 	if (err)
-		goto done;
+		return err;
 
 	if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
 		 err = got_error_from_errno("asprintf");
diff --git a/regress/cmdline/branch.sh b/regress/cmdline/branch.sh
index a2f5c35..3b0f39a 100755
--- a/regress/cmdline/branch.sh
+++ b/regress/cmdline/branch.sh
@@ -85,6 +85,24 @@ function test_branch_create {
 	ret="$?"
 	if [ "$ret" != "0" ]; then
 		echo "git checkout command failed unexpectedly"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	# Create a branch based on a specific commit
+	local commit_id=`git_show_head $testroot/repo`
+	got branch -r $testroot/repo commitbranch $commit_id
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got branch command failed unexpectedly"
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	(cd $testroot/repo && git checkout -q commitbranch)
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "git checkout command failed unexpectedly"
 	fi
 	test_done "$testroot" "$ret"
 }