summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@edwardthomson.com>2019-08-11 23:42:45 +0100
committerGitHub <noreply@github.com>2019-08-11 23:42:45 +0100
commit5774b2b13468aa3c2e7e604dd348357f6842c56a (patch)
treeb545eff2095ad84acb3533db6e7dc2b3a8dd32cb
parent42bacbc603bccf717b29cf603f825c9e6f5c1cf3 (diff)
parenta7d32d60c1fecef268100a85b6a0f8f8c824ea0e (diff)
downloadlibgit2-5774b2b13468aa3c2e7e604dd348357f6842c56a.tar.gz
Merge pull request #5113 from pks-t/pks/stash-perf
stash: avoid recomputing tree when committing worktree
-rw-r--r--examples/common.h1
-rw-r--r--examples/lg2.c1
-rw-r--r--examples/stash.c157
-rw-r--r--src/stash.c23
4 files changed, 168 insertions, 14 deletions
diff --git a/examples/common.h b/examples/common.h
index bba83217b..2ad897bca 100644
--- a/examples/common.h
+++ b/examples/common.h
@@ -70,6 +70,7 @@ extern int lg2_remote(git_repository *repo, int argc, char **argv);
extern int lg2_rev_list(git_repository *repo, int argc, char **argv);
extern int lg2_rev_parse(git_repository *repo, int argc, char **argv);
extern int lg2_show_index(git_repository *repo, int argc, char **argv);
+extern int lg2_stash(git_repository *repo, int argc, char **argv);
extern int lg2_status(git_repository *repo, int argc, char **argv);
extern int lg2_tag(git_repository *repo, int argc, char **argv);
diff --git a/examples/lg2.c b/examples/lg2.c
index 4ee0110a6..f1a8843d2 100644
--- a/examples/lg2.c
+++ b/examples/lg2.c
@@ -31,6 +31,7 @@ struct {
{ "rev-list", lg2_rev_list, 1 },
{ "rev-parse", lg2_rev_parse, 1 },
{ "show-index", lg2_show_index, 0 },
+ { "stash", lg2_stash, 1 },
{ "status", lg2_status, 1 },
{ "tag", lg2_tag, 1 },
};
diff --git a/examples/stash.c b/examples/stash.c
new file mode 100644
index 000000000..8142439c7
--- /dev/null
+++ b/examples/stash.c
@@ -0,0 +1,157 @@
+/*
+ * libgit2 "stash" example - shows how to use the stash API
+ *
+ * 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 <stdarg.h>
+
+#include "common.h"
+
+enum subcmd {
+ SUBCMD_APPLY,
+ SUBCMD_LIST,
+ SUBCMD_POP,
+ SUBCMD_PUSH
+};
+
+struct opts {
+ enum subcmd cmd;
+ int argc;
+ char **argv;
+};
+
+static void usage(const char *fmt, ...)
+{
+ va_list ap;
+
+ fputs("usage: git stash list\n", stderr);
+ fputs(" or: git stash ( pop | apply )\n", stderr);
+ fputs(" or: git stash [push]\n", stderr);
+ fputs("\n", stderr);
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+static void parse_subcommand(struct opts *opts, int argc, char *argv[])
+{
+ char *arg = (argc < 2) ? "push" : argv[1];
+ enum subcmd cmd;
+
+ if (!strcmp(arg, "apply")) {
+ cmd = SUBCMD_APPLY;
+ } else if (!strcmp(arg, "list")) {
+ cmd = SUBCMD_LIST;
+ } else if (!strcmp(arg, "pop")) {
+ cmd = SUBCMD_POP;
+ } else if (!strcmp(arg, "push")) {
+ cmd = SUBCMD_PUSH;
+ } else {
+ usage("invalid command %s", arg);
+ return;
+ }
+
+ opts->cmd = cmd;
+ opts->argc = (argc < 2) ? argc - 1 : argc - 2;
+ opts->argv = argv;
+}
+
+static int cmd_apply(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("apply does not accept any parameters");
+
+ check_lg2(git_stash_apply(repo, 0, NULL),
+ "Unable to apply stash", NULL);
+
+ return 0;
+}
+
+static int list_stash_cb(size_t index, const char *message,
+ const git_oid *stash_id, void *payload)
+{
+ UNUSED(stash_id);
+ UNUSED(payload);
+ printf("stash@{%"PRIuZ"}: %s\n", index, message);
+ return 0;
+}
+
+static int cmd_list(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("list does not accept any parameters");
+
+ check_lg2(git_stash_foreach(repo, list_stash_cb, NULL),
+ "Unable to list stashes", NULL);
+
+ return 0;
+}
+
+static int cmd_push(git_repository *repo, struct opts *opts)
+{
+ git_signature *signature;
+ git_commit *stash;
+ git_oid stashid;
+
+ if (opts->argc)
+ usage("push does not accept any parameters");
+
+ check_lg2(git_signature_default(&signature, repo),
+ "Unable to get signature", NULL);
+ check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT),
+ "Unable to save stash", NULL);
+ check_lg2(git_commit_lookup(&stash, repo, &stashid),
+ "Unable to lookup stash commit", NULL);
+
+ printf("Saved working directory %s\n", git_commit_summary(stash));
+
+ git_signature_free(signature);
+ git_commit_free(stash);
+
+ return 0;
+}
+
+static int cmd_pop(git_repository *repo, struct opts *opts)
+{
+ if (opts->argc)
+ usage("pop does not accept any parameters");
+
+ check_lg2(git_stash_pop(repo, 0, NULL),
+ "Unable to pop stash", NULL);
+
+ printf("Dropped refs/stash@{0}\n");
+
+ return 0;
+}
+
+int lg2_stash(git_repository *repo, int argc, char *argv[])
+{
+ struct opts opts = { 0 };
+
+ parse_subcommand(&opts, argc, argv);
+
+ switch (opts.cmd) {
+ case SUBCMD_APPLY:
+ return cmd_apply(repo, &opts);
+ case SUBCMD_LIST:
+ return cmd_list(repo, &opts);
+ case SUBCMD_PUSH:
+ return cmd_push(repo, &opts);
+ case SUBCMD_POP:
+ return cmd_pop(repo, &opts);
+ }
+
+ return -1;
+}
diff --git a/src/stash.c b/src/stash.c
index 2d61e6828..aa3cecf6e 100644
--- a/src/stash.c
+++ b/src/stash.c
@@ -398,28 +398,23 @@ static int commit_worktree(
git_commit *b_commit,
git_commit *u_commit)
{
- int error = 0;
- git_tree *w_tree = NULL, *i_tree = NULL;
- git_index *i_index = NULL;
- const git_commit *parents[] = { NULL, NULL, NULL };
- int ignorecase;
+ const git_commit *parents[] = { NULL, NULL, NULL };
+ git_index *i_index = NULL, *r_index = NULL;
+ git_tree *w_tree = NULL;
+ int error = 0, ignorecase;
parents[0] = b_commit;
parents[1] = i_commit;
parents[2] = u_commit;
- if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
- goto cleanup;
-
- if ((error = git_index_new(&i_index)) < 0 ||
- (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
+ if ((error = git_repository_index(&r_index, repo) < 0) ||
+ (error = git_index_new(&i_index)) < 0 ||
+ (error = git_index__fill(i_index, &r_index->entries) < 0) ||
+ (error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
goto cleanup;
git_index__set_ignore_case(i_index, ignorecase);
- if ((error = git_index_read_tree(i_index, i_tree)) < 0)
- goto cleanup;
-
if ((error = build_workdir_tree(&w_tree, repo, i_index, b_commit)) < 0)
goto cleanup;
@@ -436,9 +431,9 @@ static int commit_worktree(
parents);
cleanup:
- git_tree_free(i_tree);
git_tree_free(w_tree);
git_index_free(i_index);
+ git_index_free(r_index);
return error;
}