/*
- * Copyright (C) the libgit2 contributors. All rights reserved.
+ * libgit2 "status" example - shows how to use the status APIs
*
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
+ * Written by the libgit2 contributors
+ *
+ * To the extent possible under law, the author(s) have dedicated all copyright
+ * and related and neighboring rights to this software to the public domain
+ * worldwide. This software is distributed without any warranty.
+ *
+ * You should have received a copy of the CC0 Public Domain Dedication along
+ * with this software. If not, see
+ * <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
FORMAT_DEFAULT = 0,
FORMAT_LONG = 1,
FORMAT_SHORT = 2,
- FORMAT_PORCELAIN = 3,
+ FORMAT_PORCELAIN = 3
};
#define MAX_PATHSPEC 8
-struct opts {
- git_status_options statusopt;
- char *repodir;
- char *pathspec[MAX_PATHSPEC];
- int npaths;
- int format;
- int zterm;
- int showbranch;
+struct status_opts {
+ git_status_options statusopt;
+ char *repodir;
+ char *pathspec[MAX_PATHSPEC];
+ int npaths;
+ int format;
+ int zterm;
+ int showbranch;
+ int showsubmod;
+ int repeat;
};
-static void parse_opts(struct opts *o, int argc, char *argv[]);
+static void parse_opts(struct status_opts *o, int argc, char *argv[]);
static void show_branch(git_repository *repo, int format);
-static void print_long(git_repository *repo, git_status_list *status);
+static void print_long(git_status_list *status);
static void print_short(git_repository *repo, git_status_list *status);
+static int print_submod(git_submodule *sm, const char *name, void *payload);
-int main(int argc, char *argv[])
+int lg2_status(git_repository *repo, int argc, char *argv[])
{
- git_repository *repo = NULL;
git_status_list *status;
- struct opts o = { GIT_STATUS_OPTIONS_INIT, "." };
-
- git_threads_init();
+ struct status_opts o = { GIT_STATUS_OPTIONS_INIT, "." };
o.statusopt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
o.statusopt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
parse_opts(&o, argc, argv);
- /**
- * Try to open the repository at the given path (or at the current
- * directory if none was given).
- */
- check_lg2(git_repository_open_ext(&repo, o.repodir, 0, NULL),
- "Could not open repository", o.repodir);
-
if (git_repository_is_bare(repo))
fatal("Cannot report status on bare repository",
git_repository_path(repo));
+show_status:
+ if (o.repeat)
+ printf("\033[H\033[2J");
+
/**
* Run status on the repository
*
- * Because we want to simluate a full "git status" run and want to
- * support some command line options, we use `git_status_foreach_ext()`
- * instead of just the plain status call. This allows (a) iterating
- * over the index and then the workdir and (b) extra flags that control
- * which files are included. If you just want simple status (e.g. to
- * enumerate files that are modified) then you probably don't need the
- * extended API.
+ * We use `git_status_list_new()` to generate a list of status
+ * information which lets us iterate over it at our
+ * convenience and extract the data we want to show out of
+ * each entry.
+ *
+ * You can use `git_status_foreach()` or
+ * `git_status_foreach_ext()` if you'd prefer to execute a
+ * callback for each entry. The latter gives you more control
+ * about what results are presented.
*/
check_lg2(git_status_list_new(&status, repo, &o.statusopt),
- "Could not get status", NULL);
+ "Could not get status", NULL);
if (o.showbranch)
show_branch(repo, o.format);
+ if (o.showsubmod) {
+ int submod_count = 0;
+ check_lg2(git_submodule_foreach(repo, print_submod, &submod_count),
+ "Cannot iterate submodules", o.repodir);
+ }
+
if (o.format == FORMAT_LONG)
- print_long(repo, status);
+ print_long(status);
else
print_short(repo, status);
git_status_list_free(status);
- git_repository_free(repo);
- git_threads_shutdown();
+
+ if (o.repeat) {
+ sleep(o.repeat);
+ goto show_status;
+ }
return 0;
}
+/**
+ * If the user asked for the branch, let's show the short name of the
+ * branch.
+ */
static void show_branch(git_repository *repo, int format)
{
int error = 0;
if (error == GIT_EUNBORNBRANCH || error == GIT_ENOTFOUND)
branch = NULL;
else if (!error) {
- branch = git_reference_name(head);
- if (!strncmp(branch, "refs/heads/", strlen("refs/heads/")))
- branch += strlen("refs/heads/");
+ branch = git_reference_shorthand(head);
} else
check_lg2(error, "failed to get current branch", NULL);
git_reference_free(head);
}
-static void print_long(git_repository *repo, git_status_list *status)
+/**
+ * This function print out an output similar to git's status command
+ * in long form, including the command-line hints.
+ */
+static void print_long(git_status_list *status)
{
size_t i, maxi = git_status_list_entrycount(status);
const git_status_entry *s;
int changed_in_workdir = 0, rm_in_workdir = 0;
const char *old_path, *new_path;
- (void)repo;
-
/** Print index changes. */
for (i = 0; i < maxi; ++i) {
s = git_status_byindex(status, i);
+ /**
+ * With `GIT_STATUS_OPT_INCLUDE_UNMODIFIED` (not used in this example)
+ * `index_to_workdir` may not be `NULL` even if there are
+ * no differences, in which case it will be a `GIT_DELTA_UNMODIFIED`.
+ */
if (s->status == GIT_STATUS_CURRENT || s->index_to_workdir == NULL)
continue;
+ /** Print out the output since we know the file has some changes */
if (s->status & GIT_STATUS_WT_MODIFIED)
wstatus = "modified: ";
if (s->status & GIT_STATUS_WT_DELETED)
changed_in_workdir = 1;
printf("#\n");
}
- header = 0;
/** Print untracked files. */
printf("no changes added to commit (use \"git add\" and/or \"git commit -a\")\n");
}
+/**
+ * This version of the output prefixes each path with two status
+ * columns and shows submodule status information.
+ */
static void print_short(git_repository *repo, git_status_list *status)
{
size_t i, maxi = git_status_list_entrycount(status);
if (istatus == '?' && wstatus == '?')
continue;
+ /**
+ * A commit in a tree is how submodules are stored, so
+ * let's go take a look at its status.
+ */
if (s->index_to_workdir &&
s->index_to_workdir->new_file.mode == GIT_FILEMODE_COMMIT)
{
- git_submodule *sm = NULL;
unsigned int smstatus = 0;
- if (!git_submodule_lookup(
- &sm, repo, s->index_to_workdir->new_file.path) &&
- !git_submodule_status(&smstatus, sm))
- {
+ if (!git_submodule_status(&smstatus, repo, s->index_to_workdir->new_file.path,
+ GIT_SUBMODULE_IGNORE_UNSPECIFIED)) {
if (smstatus & GIT_SUBMODULE_STATUS_WD_MODIFIED)
extra = " (new commits)";
else if (smstatus & GIT_SUBMODULE_STATUS_WD_INDEX_MODIFIED)
}
}
+ /**
+ * Now that we have all the information, format the output.
+ */
+
if (s->head_to_index) {
a = s->head_to_index->old_file.path;
b = s->head_to_index->new_file.path;
}
}
-static void parse_opts(struct opts *o, int argc, char *argv[])
+static int print_submod(git_submodule *sm, const char *name, void *payload)
+{
+ int *count = payload;
+ (void)name;
+
+ if (*count == 0)
+ printf("# Submodules\n");
+ (*count)++;
+
+ printf("# - submodule '%s' at %s\n",
+ git_submodule_name(sm), git_submodule_path(sm));
+
+ return 0;
+}
+
+/**
+ * Parse options that git's status command supports.
+ */
+static void parse_opts(struct status_opts *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
o->statusopt.flags |= GIT_STATUS_OPT_EXCLUDE_SUBMODULES;
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
o->repodir = a + strlen("--git-dir=");
+ else if (!strcmp(a, "--repeat"))
+ o->repeat = 10;
+ else if (match_int_arg(&o->repeat, &args, "--repeat", 0))
+ /* okay */;
+ else if (!strcmp(a, "--list-submodules"))
+ o->showsubmod = 1;
else
check_lg2(-1, "Unsupported option", a);
}