Skip to content

Commit 5774b2b

Browse files
authored
Merge pull request libgit2#5113 from pks-t/pks/stash-perf
stash: avoid recomputing tree when committing worktree
2 parents 42bacbc + a7d32d6 commit 5774b2b

File tree

4 files changed

+168
-14
lines changed

4 files changed

+168
-14
lines changed

examples/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ extern int lg2_remote(git_repository *repo, int argc, char **argv);
7070
extern int lg2_rev_list(git_repository *repo, int argc, char **argv);
7171
extern int lg2_rev_parse(git_repository *repo, int argc, char **argv);
7272
extern int lg2_show_index(git_repository *repo, int argc, char **argv);
73+
extern int lg2_stash(git_repository *repo, int argc, char **argv);
7374
extern int lg2_status(git_repository *repo, int argc, char **argv);
7475
extern int lg2_tag(git_repository *repo, int argc, char **argv);
7576

examples/lg2.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct {
3131
{ "rev-list", lg2_rev_list, 1 },
3232
{ "rev-parse", lg2_rev_parse, 1 },
3333
{ "show-index", lg2_show_index, 0 },
34+
{ "stash", lg2_stash, 1 },
3435
{ "status", lg2_status, 1 },
3536
{ "tag", lg2_tag, 1 },
3637
};

examples/stash.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
/*
2+
* libgit2 "stash" example - shows how to use the stash API
3+
*
4+
* Written by the libgit2 contributors
5+
*
6+
* To the extent possible under law, the author(s) have dedicated all copyright
7+
* and related and neighboring rights to this software to the public domain
8+
* worldwide. This software is distributed without any warranty.
9+
*
10+
* You should have received a copy of the CC0 Public Domain Dedication along
11+
* with this software. If not, see
12+
* <http://creativecommons.org/publicdomain/zero/1.0/>.
13+
*/
14+
15+
#include <stdarg.h>
16+
17+
#include "common.h"
18+
19+
enum subcmd {
20+
SUBCMD_APPLY,
21+
SUBCMD_LIST,
22+
SUBCMD_POP,
23+
SUBCMD_PUSH
24+
};
25+
26+
struct opts {
27+
enum subcmd cmd;
28+
int argc;
29+
char **argv;
30+
};
31+
32+
static void usage(const char *fmt, ...)
33+
{
34+
va_list ap;
35+
36+
fputs("usage: git stash list\n", stderr);
37+
fputs(" or: git stash ( pop | apply )\n", stderr);
38+
fputs(" or: git stash [push]\n", stderr);
39+
fputs("\n", stderr);
40+
41+
va_start(ap, fmt);
42+
vfprintf(stderr, fmt, ap);
43+
va_end(ap);
44+
45+
exit(1);
46+
}
47+
48+
static void parse_subcommand(struct opts *opts, int argc, char *argv[])
49+
{
50+
char *arg = (argc < 2) ? "push" : argv[1];
51+
enum subcmd cmd;
52+
53+
if (!strcmp(arg, "apply")) {
54+
cmd = SUBCMD_APPLY;
55+
} else if (!strcmp(arg, "list")) {
56+
cmd = SUBCMD_LIST;
57+
} else if (!strcmp(arg, "pop")) {
58+
cmd = SUBCMD_POP;
59+
} else if (!strcmp(arg, "push")) {
60+
cmd = SUBCMD_PUSH;
61+
} else {
62+
usage("invalid command %s", arg);
63+
return;
64+
}
65+
66+
opts->cmd = cmd;
67+
opts->argc = (argc < 2) ? argc - 1 : argc - 2;
68+
opts->argv = argv;
69+
}
70+
71+
static int cmd_apply(git_repository *repo, struct opts *opts)
72+
{
73+
if (opts->argc)
74+
usage("apply does not accept any parameters");
75+
76+
check_lg2(git_stash_apply(repo, 0, NULL),
77+
"Unable to apply stash", NULL);
78+
79+
return 0;
80+
}
81+
82+
static int list_stash_cb(size_t index, const char *message,
83+
const git_oid *stash_id, void *payload)
84+
{
85+
UNUSED(stash_id);
86+
UNUSED(payload);
87+
printf("stash@{%"PRIuZ"}: %s\n", index, message);
88+
return 0;
89+
}
90+
91+
static int cmd_list(git_repository *repo, struct opts *opts)
92+
{
93+
if (opts->argc)
94+
usage("list does not accept any parameters");
95+
96+
check_lg2(git_stash_foreach(repo, list_stash_cb, NULL),
97+
"Unable to list stashes", NULL);
98+
99+
return 0;
100+
}
101+
102+
static int cmd_push(git_repository *repo, struct opts *opts)
103+
{
104+
git_signature *signature;
105+
git_commit *stash;
106+
git_oid stashid;
107+
108+
if (opts->argc)
109+
usage("push does not accept any parameters");
110+
111+
check_lg2(git_signature_default(&signature, repo),
112+
"Unable to get signature", NULL);
113+
check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT),
114+
"Unable to save stash", NULL);
115+
check_lg2(git_commit_lookup(&stash, repo, &stashid),
116+
"Unable to lookup stash commit", NULL);
117+
118+
printf("Saved working directory %s\n", git_commit_summary(stash));
119+
120+
git_signature_free(signature);
121+
git_commit_free(stash);
122+
123+
return 0;
124+
}
125+
126+
static int cmd_pop(git_repository *repo, struct opts *opts)
127+
{
128+
if (opts->argc)
129+
usage("pop does not accept any parameters");
130+
131+
check_lg2(git_stash_pop(repo, 0, NULL),
132+
"Unable to pop stash", NULL);
133+
134+
printf("Dropped refs/stash@{0}\n");
135+
136+
return 0;
137+
}
138+
139+
int lg2_stash(git_repository *repo, int argc, char *argv[])
140+
{
141+
struct opts opts = { 0 };
142+
143+
parse_subcommand(&opts, argc, argv);
144+
145+
switch (opts.cmd) {
146+
case SUBCMD_APPLY:
147+
return cmd_apply(repo, &opts);
148+
case SUBCMD_LIST:
149+
return cmd_list(repo, &opts);
150+
case SUBCMD_PUSH:
151+
return cmd_push(repo, &opts);
152+
case SUBCMD_POP:
153+
return cmd_pop(repo, &opts);
154+
}
155+
156+
return -1;
157+
}

src/stash.c

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -398,28 +398,23 @@ static int commit_worktree(
398398
git_commit *b_commit,
399399
git_commit *u_commit)
400400
{
401-
int error = 0;
402-
git_tree *w_tree = NULL, *i_tree = NULL;
403-
git_index *i_index = NULL;
404-
const git_commit *parents[] = { NULL, NULL, NULL };
405-
int ignorecase;
401+
const git_commit *parents[] = { NULL, NULL, NULL };
402+
git_index *i_index = NULL, *r_index = NULL;
403+
git_tree *w_tree = NULL;
404+
int error = 0, ignorecase;
406405

407406
parents[0] = b_commit;
408407
parents[1] = i_commit;
409408
parents[2] = u_commit;
410409

411-
if ((error = git_commit_tree(&i_tree, i_commit)) < 0)
412-
goto cleanup;
413-
414-
if ((error = git_index_new(&i_index)) < 0 ||
415-
(error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
410+
if ((error = git_repository_index(&r_index, repo) < 0) ||
411+
(error = git_index_new(&i_index)) < 0 ||
412+
(error = git_index__fill(i_index, &r_index->entries) < 0) ||
413+
(error = git_repository__configmap_lookup(&ignorecase, repo, GIT_CONFIGMAP_IGNORECASE)) < 0)
416414
goto cleanup;
417415

418416
git_index__set_ignore_case(i_index, ignorecase);
419417

420-
if ((error = git_index_read_tree(i_index, i_tree)) < 0)
421-
goto cleanup;
422-
423418
if ((error = build_workdir_tree(&w_tree, repo, i_index, b_commit)) < 0)
424419
goto cleanup;
425420

@@ -436,9 +431,9 @@ static int commit_worktree(
436431
parents);
437432

438433
cleanup:
439-
git_tree_free(i_tree);
440434
git_tree_free(w_tree);
441435
git_index_free(i_index);
436+
git_index_free(r_index);
442437
return error;
443438
}
444439

0 commit comments

Comments
 (0)