From ba95c01249c5a46c6671f0c5f95c69c13319bdab Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Fri, 5 Aug 2016 09:22:37 -0300 Subject: [PATCH] eeshow/: detect if repo is dirty and add history entry with commit = NULL --- eeshow/git-hist.c | 34 +++++++++++++++++++++++++-------- eeshow/git-hist.h | 2 +- eeshow/git-util.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++ eeshow/git-util.h | 6 ++++++ 4 files changed, 81 insertions(+), 9 deletions(-) diff --git a/eeshow/git-hist.c b/eeshow/git-hist.c index 3367b9d..1baca2f 100644 --- a/eeshow/git-hist.c +++ b/eeshow/git-hist.c @@ -142,7 +142,7 @@ bool vcs_git_try(const char *path) struct hist *vcs_git_hist(const char *path) { - struct hist *head; + struct hist *head, *dirty; git_repository *repo; git_oid oid; const git_error *e; @@ -173,7 +173,17 @@ struct hist *vcs_git_hist(const char *path) } recurse(head, 1, &head); - return head; + + if (!git_repo_is_dirty(repo)) + return head; + + dirty = new_commit(0); + dirty->older = alloc_type(struct hist *); + dirty->older[0] = head; + dirty->n_older = 1; + uplink(head, dirty); + + return dirty; } @@ -182,6 +192,8 @@ const char *vcs_git_summary(struct hist *h) const char *summary; const git_error *e; + if (!h->commit) + return "Uncommitted changes"; summary = git_commit_summary(h->commit); if (summary) return summary; @@ -210,13 +222,19 @@ void dump_hist(struct hist *h) const git_error *e; unsigned i; - if (git_object_short_id(&buf, (git_object *) h->commit)) { - e = giterr_last(); - fprintf(stderr, "git_object_short_id: %s\n", e->message); - exit(1); + if (h->commit) { + if (git_object_short_id(&buf, (git_object *) h->commit)) { + e = giterr_last(); + fprintf(stderr, "git_object_short_id: %s\n", + e->message); + exit(1); + } + printf("%*s%s %s\n", + 2 * h->branch, "", buf.ptr, vcs_git_summary(h)); + git_buf_free(&buf); + } else { + printf("dirty\n"); } - printf("%*s%s %s\n", 2 * h->branch, "", buf.ptr, vcs_git_summary(h)); - git_buf_free(&buf); for (i = 0; i != h->n_older; i++) if (h->older[i]->newer[h->older[i]->n_newer - 1] == h) diff --git a/eeshow/git-hist.h b/eeshow/git-hist.h index 2d1b628..9c394ed 100644 --- a/eeshow/git-hist.h +++ b/eeshow/git-hist.h @@ -19,7 +19,7 @@ struct hist { - struct git_commit *commit; + struct git_commit *commit; /* NULL if uncommitted changes */ unsigned branch; /* branch index */ diff --git a/eeshow/git-util.c b/eeshow/git-util.c index 71cf6cd..e3bd2af 100644 --- a/eeshow/git-util.c +++ b/eeshow/git-util.c @@ -11,12 +11,60 @@ */ #include +#include #include #include "git-util.h" +/* + * This seems to be an efficient way for finding out if a repo is dirty. + * + * http://ben.straub.cc/2013/04/02/libgit2-checkout/ + * + * References: + * https://libgit2.github.com/libgit2/#HEAD/group/checkout/git_checkout_index + * https://libgit2.github.com/libgit2/#HEAD/type/git_checkout_options + * https://github.com/libgit2/libgit2/blob/HEAD/include/git2/checkout.h#L251-295 + */ + + +static int checkout_notify_cb(git_checkout_notify_t why, + const char *path, const git_diff_file *baseline, + const git_diff_file *target, const git_diff_file *workdir, + void *payload) +{ + bool *res = payload; + + assert(why == GIT_CHECKOUT_NOTIFY_DIRTY); + + *res = 1; + return 0; +} + + +bool git_repo_is_dirty(git_repository *repo) +{ + git_checkout_options opts; + bool res = 0; + + /* + * Initialization with GIT_CHECKOUT_OPTIONS_INIT complains about not + * setting checkout_strategy. git_checkout_init_options is fine. + */ + git_checkout_init_options(&opts, GIT_CHECKOUT_OPTIONS_VERSION); + opts.checkout_strategy = GIT_CHECKOUT_NONE; + /* let's be explicit about this */ + opts.notify_flags = GIT_CHECKOUT_NOTIFY_DIRTY; + opts.notify_cb = checkout_notify_cb; + opts.notify_payload = &res; + git_checkout_index(repo, NULL, &opts); + + return res; +} + + /* * Git documentation says that git_libgit2_init can be called more then once * but doesn't quite what happens then, e.g., whether references obtained diff --git a/eeshow/git-util.h b/eeshow/git-util.h index 601855a..54641e5 100644 --- a/eeshow/git-util.h +++ b/eeshow/git-util.h @@ -13,6 +13,12 @@ #ifndef GIT_UTIL_H #define GIT_UTIL_H +#include + +#include + + +bool git_repo_is_dirty(git_repository *repo); void git_init_once(void); #endif /* !GIT_UTIL_H */