Commit 0bb8a95e464401b5b664287c73785c6d9d7a5a59

Stefan Sperling 2018-03-12T22:00:08

add support for checking out a subtree

diff --git a/got/got.1 b/got/got.1
index 1a35ccf..c281528 100644
--- a/got/got.1
+++ b/got/got.1
@@ -20,7 +20,7 @@
 .Nm got
 .Nd simple version control system
 .Sh SYNOPSIS
-.Nm 
+.Nm
 .Ar command
 .Op Fl h
 .Op Ar arg ...
@@ -39,9 +39,11 @@ Display usage information.
 .El
 .Pp
 The commands are as follows:
-.Bl -tag -width Ds
-.It Cm status
-Show current status of files.
+.Bl -tag -width checkout
+.It Cm checkout
+Copy files from a repository into a new work tree.
+.\".It Cm status
+.\"Show current status of files.
 .It Cm log
 Display history of the repository.
 .El
diff --git a/got/got.c b/got/got.c
index 68caca6..be95ec2 100644
--- a/got/got.c
+++ b/got/got.c
@@ -53,7 +53,7 @@ const struct got_error*		cmd_status(int, char *[]);
 
 struct cmd got_commands[] = {
 	{ "checkout",	cmd_checkout,	usage_checkout,
-	    "check out a work tree from a repository" },
+	    "check out a new work tree from a repository" },
 	{ "log",	cmd_log,	usage_log,
 	    "show repository history" },
 #ifdef notyet
@@ -130,8 +130,8 @@ usage(void)
 __dead void
 usage_checkout(void)
 {
-	fprintf(stderr, "usage: %s checkout REPO_PATH [WORKTREE_PATH]\n",
-	    getprogname());
+	fprintf(stderr, "usage: %s checkout [-p prefix] repository-path "
+	    "[worktree-path]\n", getprogname());
 	exit(1);
 }
 
@@ -155,13 +155,30 @@ cmd_checkout(int argc, char *argv[])
 	struct got_worktree *worktree = NULL;
 	char *repo_path = NULL;
 	char *worktree_path = NULL;
+	const char *path_prefix = "";
+	int ch;
+
+	optind = 0;
+	while ((ch = getopt(argc, argv, "p:")) != -1) {
+		switch (ch) {
+		case 'p':
+			path_prefix = optarg;
+			break;
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+
+	argc -= optind;
+	argv += optind;
 
 	if (pledge("stdio rpath wpath cpath flock", NULL) == -1)
 		err(1, "pledge");
 
-	if (argc == 2) {
+	if (argc == 1) {
 		char *cwd, *base, *dotgit;
-		repo_path = argv[1];
+		repo_path = argv[0];
 		cwd = getcwd(NULL, 0);
 		if (cwd == NULL)
 			err(1, "getcwd");
@@ -176,9 +193,9 @@ cmd_checkout(int argc, char *argv[])
 			return got_error(GOT_ERR_NO_MEM);
 		}
 		free(cwd);
-	} else if (argc == 3) {
-		repo_path = argv[1];
-		worktree_path = strdup(argv[2]);
+	} else if (argc == 2) {
+		repo_path = argv[0];
+		worktree_path = strdup(argv[1]);
 		if (worktree_path == NULL)
 			return got_error(GOT_ERR_NO_MEM);
 	} else
@@ -191,7 +208,7 @@ cmd_checkout(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	error = got_worktree_init(worktree_path, head_ref, "/", repo);
+	error = got_worktree_init(worktree_path, head_ref, path_prefix, repo);
 	if (error != NULL)
 		goto done;
 
@@ -267,7 +284,7 @@ print_commit_object(struct got_object *obj, struct got_object_id *id,
 __dead void
 usage_log(void)
 {
-	fprintf(stderr, "usage: %s log [REPO_PATH]\n", getprogname());
+	fprintf(stderr, "usage: %s log [repository-path]\n", getprogname());
 	exit(1);
 }
 
diff --git a/lib/worktree.c b/lib/worktree.c
index 0df2fb5..a1bff6f 100644
--- a/lib/worktree.c
+++ b/lib/worktree.c
@@ -158,9 +158,12 @@ got_worktree_init(const char *path, struct got_reference *head_ref,
 	char *refstr = NULL;
 	char *repo_path = NULL;
 	char *formatstr = NULL;
+	char *absprefix = NULL;
 
-	if (!got_path_is_absolute(prefix))
-		return got_error(GOT_ERR_BAD_PATH);
+	if (!got_path_is_absolute(prefix)) {
+		if (asprintf(&absprefix, "/%s", prefix) == -1)
+			return got_error(GOT_ERR_NO_MEM);
+	}
 
 	/* Create top-level directory (may already exist). */
 	if (mkdir(path, GOT_DEFAULT_DIR_MODE) == -1 && errno != EEXIST) {
@@ -209,7 +212,8 @@ got_worktree_init(const char *path, struct got_reference *head_ref,
 		goto done;
 
 	/* Store in-repository path prefix. */
-	err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX, prefix);
+	err = create_meta_file(path_got, GOT_WORKTREE_PATH_PREFIX,
+	    absprefix ? absprefix : prefix);
 	if (err)
 		goto done;
 
@@ -227,6 +231,7 @@ done:
 	free(formatstr);
 	free(refstr);
 	free(repo_path);
+	free(absprefix);
 	return err;
 }