commit - d01904d4bba62d3608e53c5f4940a408d3353370
commit + 4e759de49807996b58bace13158d54df47e7717e
blob - d7cc1a04da9d814d794c71616fa488d5edd96dfb
blob + faa6c4d2707477f3e5482355a69ab2f68951a36d
--- got/got.1
+++ got/got.1
List all existing references in the repository.
.It Fl d Ar name
Delete the reference with the specified name from the repository.
+.El
+.It Cm branch [ Fl r Ar repository-path ] [ Fl l ] [ Fl d Ar name ] [ Ar name [ Ar base-branch ] ]
+Manage branches in a repository.
+.Pp
+Branches are managed via references which live in the
+.Dq refs/heads/
+reference namespace.
+The
+.Cm got branch
+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
+.Ar name ,
+and make it point at the given
+.Ar base-branch .
+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.
+.Pp
+The options for
+.Cm got branch
+are as follows:
+.Bl -tag -width Ds
+.It Fl r Ar repository-path
+Use the repository at the specified path.
+If not specified, assume the repository is located at or above the current
+working directory.
+If this directory is a
+.Nm
+work tree, use the repository path associated with this work tree.
+.It Fl l
+List all existing branches in the repository.
+.It Fl d Ar name
+Delete the branch with the specified name from the repository.
.El
.It Cm add Ar file-path ...
Schedule unversioned files in a work tree for addition to the
.Pp
In a work tree or a git repository directory, list all branch references:
.Pp
-.Dl $ got ref -l | grep ^refs/heads
+.Dl $ got branch -l
.Pp
In a work tree or a git repository directory, create a new branch called
.Dq unified-buffer-cache
.Dq master
branch:
.Pp
-.Dl $ got ref refs/heads/unified-buffer-cache refs/heads/master
+.Dl $ got branch unified-buffer-cache master
.Pp
Switch an existing work tree to the branch
.Dq unified-buffer-cache .
blob - 8787eff3dc915827732a1e6e2f48996dbab376a6
blob + a4975d670ed06aa6ed6696642cd7e23b2e0a0ee9
--- got/got.c
+++ got/got.c
__dead static void usage_tree(void);
__dead static void usage_status(void);
__dead static void usage_ref(void);
+__dead static void usage_branch(void);
__dead static void usage_add(void);
__dead static void usage_rm(void);
__dead static void usage_revert(void);
static const struct got_error* cmd_tree(int, char *[]);
static const struct got_error* cmd_status(int, char *[]);
static const struct got_error* cmd_ref(int, char *[]);
+static const struct got_error* cmd_branch(int, char *[]);
static const struct got_error* cmd_add(int, char *[]);
static const struct got_error* cmd_rm(int, char *[]);
static const struct got_error* cmd_revert(int, char *[]);
{ "tree", cmd_tree, usage_tree },
{ "status", cmd_status, usage_status },
{ "ref", cmd_ref, usage_ref },
+ { "branch", cmd_branch, usage_branch },
{ "add", cmd_add, usage_add },
{ "rm", cmd_rm, usage_rm },
{ "revert", cmd_revert, usage_revert },
error = delete_ref(repo, delref);
else
error = add_ref(repo, argv[0], argv[1]);
+done:
+ if (repo)
+ got_repo_close(repo);
+ if (worktree)
+ got_worktree_close(worktree);
+ free(cwd);
+ free(repo_path);
+ return error;
+}
+
+__dead static void
+usage_branch(void)
+{
+ fprintf(stderr,
+ "usage: %s branch [-r repository] -l | -d name | "
+ "name [base-branch]\n", getprogname());
+ exit(1);
+}
+
+static const struct got_error *
+list_branches(struct got_repository *repo)
+{
+ static const struct got_error *err = NULL;
+ struct got_reflist_head refs;
+ struct got_reflist_entry *re;
+
+ SIMPLEQ_INIT(&refs);
+ err = got_ref_list(&refs, repo);
+ if (err)
+ return err;
+
+ SIMPLEQ_FOREACH(re, &refs, entry) {
+ const char *refname;
+ char *refstr;
+ refname = got_ref_get_name(re->ref);
+ if (strncmp(refname, "refs/heads/", 11) != 0)
+ continue;
+ refname += 11;
+ refstr = got_ref_to_str(re->ref);
+ if (refstr == NULL)
+ return got_error_from_errno("got_ref_to_str");
+ printf("%s: %s\n", refname, refstr);
+ free(refstr);
+ }
+
+ got_ref_list_free(&refs);
+ return NULL;
+}
+
+static const struct got_error *
+delete_branch(struct got_repository *repo, const char *branch_name)
+{
+ const struct got_error *err = NULL;
+ struct got_reference *ref;
+ char *refname;
+
+ if (asprintf(&refname, "refs/heads/%s", branch_name) == -1)
+ return got_error_from_errno("asprintf");
+
+ err = got_ref_open(&ref, repo, refname, 0);
+ if (err)
+ goto done;
+
+ err = got_ref_delete(ref, repo);
+ got_ref_close(ref);
+done:
+ free(refname);
+ return err;
+}
+
+static const struct got_error *
+add_branch(struct got_repository *repo, const char *branch_name,
+ const char *base_branch)
+{
+ const struct got_error *err = NULL;
+ struct got_object_id *id = NULL;
+ struct got_reference *ref = NULL;
+ char *base_refname = NULL, *refname = NULL;
+ struct got_reference *base_ref;
+
+ 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);
+ if (err)
+ goto done;
+
+ if (asprintf(&refname, "refs/heads/%s", branch_name) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+
+ err = got_ref_open(&ref, repo, refname, 0);
+ if (err == NULL) {
+ err = got_error(GOT_ERR_BRANCH_EXISTS);
+ goto done;
+ } else if (err->code != GOT_ERR_NOT_REF)
+ goto done;
+
+ err = got_ref_alloc(&ref, refname, id);
+ if (err)
+ goto done;
+
+ err = got_ref_write(ref, repo);
done:
+ if (ref)
+ got_ref_close(ref);
+ free(id);
+ free(base_refname);
+ free(refname);
+ return err;
+}
+
+static const struct got_error *
+cmd_branch(int argc, char *argv[])
+{
+ const struct got_error *error = NULL;
+ struct got_repository *repo = NULL;
+ struct got_worktree *worktree = NULL;
+ char *cwd = NULL, *repo_path = NULL;
+ int ch, do_list = 0;
+ const char *delref = NULL;
+
+ while ((ch = getopt(argc, argv, "d:r:l")) != -1) {
+ switch (ch) {
+ case 'd':
+ delref = optarg;
+ break;
+ case 'r':
+ repo_path = realpath(optarg, NULL);
+ if (repo_path == NULL)
+ err(1, "-r option");
+ got_path_strip_trailing_slashes(repo_path);
+ break;
+ case 'l':
+ do_list = 1;
+ break;
+ default:
+ usage_branch();
+ /* NOTREACHED */
+ }
+ }
+
+ if (do_list && delref)
+ errx(1, "-l and -d options are mutually exclusive\n");
+
+ argc -= optind;
+ argv += optind;
+
+ if (do_list || delref) {
+ if (argc > 0)
+ usage_branch();
+ } else if (argc < 1 || argc > 2)
+ usage_branch();
+
+#ifndef PROFILE
+ if (do_list) {
+ if (pledge("stdio rpath wpath flock proc exec sendfd unveil",
+ NULL) == -1)
+ err(1, "pledge");
+ } else {
+ if (pledge("stdio rpath wpath cpath fattr flock proc exec "
+ "sendfd unveil", NULL) == -1)
+ err(1, "pledge");
+ }
+#endif
+ cwd = getcwd(NULL, 0);
+ if (cwd == NULL) {
+ error = got_error_from_errno("getcwd");
+ goto done;
+ }
+
+ if (repo_path == NULL) {
+ error = got_worktree_open(&worktree, cwd);
+ if (error && error->code != GOT_ERR_NOT_WORKTREE)
+ goto done;
+ else
+ error = NULL;
+ if (worktree) {
+ repo_path =
+ strdup(got_worktree_get_repo_path(worktree));
+ if (repo_path == NULL)
+ error = got_error_from_errno("strdup");
+ if (error)
+ goto done;
+ } else {
+ repo_path = strdup(cwd);
+ if (repo_path == NULL) {
+ error = got_error_from_errno("strdup");
+ goto done;
+ }
+ }
+ }
+
+ error = got_repo_open(&repo, repo_path);
+ if (error != NULL)
+ goto done;
+
+ error = apply_unveil(got_repo_get_path(repo), do_list,
+ worktree ? got_worktree_get_root_path(worktree) : NULL, 0);
+ if (error)
+ goto done;
+
+ if (do_list)
+ error = list_branches(repo);
+ else if (delref)
+ error = delete_branch(repo, delref);
+ else {
+ const char *base_branch;
+ if (argc == 1) {
+ base_branch = worktree ?
+ got_worktree_get_head_ref_name(worktree) :
+ GOT_REF_HEAD;
+ } else
+ base_branch = argv[1];
+ error = add_branch(repo, argv[0], base_branch);
+ }
+done:
if (repo)
got_repo_close(repo);
if (worktree)
blob - 0186e720548b6da8fde30b6fd002a9076c3adc16
blob + c05ac929d21262fe260f6843312f25459fc4a06d
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_ROOT_COMMIT 80
#define GOT_ERR_MIXED_COMMITS 81
#define GOT_ERR_CONFLICTS 82
+#define GOT_ERR_BRANCH_EXISTS 83
static const struct got_error {
int code;
"base commits; the entire work tree must be updated first" },
{ GOT_ERR_CONFLICTS, "work tree contains conflicted files; these "
"conflicts must be resolved first" },
+ { GOT_ERR_BRANCH_EXISTS,"specified branch already exists" },
};
/*