commit - 5166488913ca69fd4d6c284f8bee054b6bf1d073
commit + 5c860e2997733fa54f69d9b201bc1cf49a3f78b8
blob - /dev/null
blob + 0ce0ba7559ff21826796e2eee3bf9e71e2155a0a (mode 644)
--- /dev/null
+++ got/Makefile
+
+PROG= got
+SRCS= got.c
+
+CFLAGS+= -W -Wall -Wstrict-prototypes -Wunused-variable
+
+# libgit2
+CFLAGS+= -I/usr/local/include
+LDADD+= -L/usr/local/lib -lgit2
+
+.include <bsd.prog.mk>
blob - /dev/null
blob + ccb72f27598eb28ba66f1e58c05bbfe0924d612e (mode 644)
--- /dev/null
+++ got/got.1
+.\"
+.\" Copyright (c) 2017 Martin Pieuchot
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd $Mdocdate$
+.Dt GOT 1
+.Os
+.Sh NAME
+.Nm got
+.Nd simple version control system
+.Sh SYNOPSIS
+.Nm
+.Ar command
+.Op Ar arg ...
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to manage
+.Xr git 5
+repositories.
+It prioritizes ease of use and simplicity over flexibility.
+.Pp
+The commands are as follows:
+.Bl -tag -width Ds
+.It Cm status
+Show current status of files.
+.It Cm log
+Display history of the repository.
+.El
+.Sh EXIT STATUS
+.Ex -std got
+.Sh SEE ALSO
+.Xr git 5
blob - /dev/null
blob + c18fa2fa6c3903b079ad2f7d4fee3d22ea7c9c1c (mode 644)
--- /dev/null
+++ got/got.c
+/*
+ * Copyright (c) 2017 Martin Pieuchot
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <err.h>
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <git2.h>
+
+#ifndef nitems
+#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
+#endif
+
+struct cmd {
+ const char *cmd_name;
+ int (*cmd_main)(int, char *[]);
+};
+
+__dead void usage(void);
+
+int cmd_log(int, char *[]);
+int cmd_status(int, char *[]);
+
+struct cmd got_commands[] = {
+ { "log", cmd_log },
+ { "status", cmd_status },
+};
+
+int
+main(int argc, char *argv[])
+{
+ struct cmd *cmd;
+ unsigned int i;
+ int ch;
+
+ setlocale(LC_ALL, "");
+
+ if (pledge("stdio rpath", NULL) == -1)
+ err(1, "pledge");
+
+ while ((ch = getopt(argc, argv, "")) != -1) {
+ switch (ch) {
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc <= 0)
+ usage();
+
+ for (i = 0; i < nitems(got_commands); i++) {
+ cmd = &got_commands[i];
+
+ if (strncmp(cmd->cmd_name, argv[0], strlen(argv[0])))
+ continue;
+
+ return got_commands[i].cmd_main(argc, argv);
+ /* NOTREACHED */
+ }
+
+ fprintf(stderr, "%s: unknown command -- %s\n", getprogname(), argv[0]);
+ return 1;
+}
+
+__dead void
+usage(void)
+{
+ fprintf(stderr, "usage: %s command [arg ...]\n", getprogname());
+ exit(1);
+}
+
+int
+cmd_log(int argc __unused, char *argv[] __unused)
+{
+ git_repository *repo = NULL;
+ git_revwalk *walker = NULL;
+ git_commit *commit = NULL;
+ git_oid oid;
+
+ git_libgit2_init();
+
+ if (git_repository_open_ext(&repo, ".", 0, NULL))
+ errx(1, "git_repository_open: %s", giterr_last()->message);
+
+ if (git_revwalk_new(&walker, repo))
+ errx(1, "git_revwalk_new: %s", giterr_last()->message);
+
+ if (git_revwalk_push_head(walker))
+ errx(1, "git_revwalk_push_head: %s", giterr_last()->message);
+
+ while (git_revwalk_next(&oid, walker) == 0) {
+ char buf[GIT_OID_HEXSZ + 1];
+ const git_signature *sig;
+
+ git_commit_free(commit);
+ if (git_commit_lookup(&commit, repo, &oid))
+ errx(1, "git_commit_lookup: %s", giterr_last()->message);
+
+ printf("-----------------------------------------------\n");
+ git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
+ printf("commit %s\n", buf);
+
+ if ((sig = git_commit_author(commit)) != NULL) {
+ printf("Author: %s <%s>\n", sig->name, sig->email);
+ }
+ printf("\n%s\n", git_commit_message_raw(commit));
+ }
+ git_commit_free(commit);
+
+ git_repository_free(repo);
+ git_libgit2_shutdown();
+
+ return 0;
+}
+
+int
+cmd_status(int argc __unused, char *argv[] __unused)
+{
+ git_repository *repo = NULL;
+ git_status_list *status;
+ git_status_options statusopts;
+ size_t i;
+
+ git_libgit2_init();
+
+ if (git_repository_open_ext(&repo, ".", 0, NULL))
+ errx(1, "git_repository_open: %s", giterr_last()->message);
+
+ if (git_repository_is_bare(repo))
+ errx(1, "bar repository");
+
+ if (git_status_init_options(&statusopts, GIT_STATUS_OPTIONS_VERSION))
+ errx(1, "git_status_init_options: %s", giterr_last()->message);
+
+ statusopts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
+ statusopts.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
+ GIT_STATUS_OPT_RENAMES_HEAD_TO_INDEX |
+ GIT_STATUS_OPT_SORT_CASE_SENSITIVELY;
+
+ if (git_status_list_new(&status, repo, &statusopts))
+ errx(1, "git_status_list_new: %s", giterr_last()->message);
+
+ for (i = 0; i < git_status_list_entrycount(status); i++) {
+ const git_status_entry *se;
+
+ se = git_status_byindex(status, i);
+ switch (se->status) {
+ case GIT_STATUS_WT_NEW:
+ printf("? %s\n", se->index_to_workdir->new_file.path);
+ break;
+ case GIT_STATUS_WT_MODIFIED:
+ printf("M %s\n", se->index_to_workdir->new_file.path);
+ break;
+ case GIT_STATUS_WT_DELETED:
+ printf("R %s\n", se->index_to_workdir->new_file.path);
+ break;
+ case GIT_STATUS_WT_RENAMED:
+ printf("m %s -> %s\n",
+ se->index_to_workdir->old_file.path,
+ se->index_to_workdir->new_file.path);
+ break;
+ case GIT_STATUS_WT_TYPECHANGE:
+ printf("t %s\n", se->index_to_workdir->new_file.path);
+ break;
+ case GIT_STATUS_INDEX_NEW:
+ printf("A %s\n", se->head_to_index->new_file.path);
+ break;
+ case GIT_STATUS_INDEX_MODIFIED:
+ printf("M %s\n", se->head_to_index->old_file.path);
+ break;
+ case GIT_STATUS_INDEX_DELETED:
+ printf("R %s\n", se->head_to_index->old_file.path);
+ break;
+ case GIT_STATUS_INDEX_RENAMED:
+ printf("m %s -> %s\n",
+ se->head_to_index->old_file.path,
+ se->head_to_index->new_file.path);
+ break;
+ case GIT_STATUS_INDEX_TYPECHANGE:
+ printf("t %s\n", se->head_to_index->old_file.path);
+ break;
+ case GIT_STATUS_CURRENT:
+ default:
+ break;
+ }
+ }
+
+ git_status_list_free(status);
+ git_repository_free(repo);
+ git_libgit2_shutdown();
+
+ return 0;
+}