Skip to content

Commit 0c5583a

Browse files
pks-tgitster
authored andcommitted
add-patch: add support for in-memory index patching
With `run_add_p()` callers have the ability to apply changes from a specific revision to a repository's index. This infra supports several different modes, like for example applying changes to the index, working tree or both. One feature that is missing though is the ability to apply changes to an in-memory index different from the repository's index. Add a new function `run_add_p_index()` to plug this gap. This new function will be used in a subsequent commit. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent d51b61f commit 0c5583a

2 files changed

Lines changed: 132 additions & 25 deletions

File tree

add-patch.c

Lines changed: 124 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
#include "git-compat-util.h"
55
#include "add-patch.h"
66
#include "advice.h"
7+
#include "commit.h"
78
#include "config.h"
89
#include "diff.h"
910
#include "editor.h"
1011
#include "environment.h"
1112
#include "gettext.h"
13+
#include "hex.h"
1214
#include "object-name.h"
1315
#include "pager.h"
1416
#include "read-cache-ll.h"
@@ -263,6 +265,8 @@ struct hunk {
263265

264266
struct add_p_state {
265267
struct repository *r;
268+
struct index_state *index;
269+
const char *index_file;
266270
struct interactive_config cfg;
267271
struct strbuf answer, buf;
268272

@@ -438,7 +442,7 @@ static void setup_child_process(struct add_p_state *s,
438442

439443
cp->git_cmd = 1;
440444
strvec_pushf(&cp->env,
441-
INDEX_ENVIRONMENT "=%s", s->r->index_file);
445+
INDEX_ENVIRONMENT "=%s", s->index_file);
442446
}
443447

444448
static int parse_range(const char **p,
@@ -1559,7 +1563,7 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
15591563
strbuf_reset(&s->buf);
15601564
reassemble_patch(s, file_diff, 0, &s->buf);
15611565

1562-
discard_index(s->r->index);
1566+
discard_index(s->index);
15631567
if (s->mode->apply_for_checkout)
15641568
apply_for_checkout(s, &s->buf,
15651569
s->mode->is_reverse);
@@ -1570,9 +1574,11 @@ static void apply_patch(struct add_p_state *s, struct file_diff *file_diff)
15701574
NULL, 0, NULL, 0))
15711575
error(_("'git apply' failed"));
15721576
}
1573-
if (repo_read_index(s->r) >= 0)
1577+
if (read_index_from(s->index, s->index_file, s->r->gitdir) >= 0 &&
1578+
s->index == s->r->index) {
15741579
repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0,
15751580
1, NULL, NULL, NULL);
1581+
}
15761582
}
15771583

15781584
}
@@ -1996,18 +2002,51 @@ static size_t patch_update_file(struct add_p_state *s, size_t idx)
19962002
return patch_update_resp;
19972003
}
19982004

2005+
static int run_add_p_common(struct add_p_state *state,
2006+
const struct pathspec *ps)
2007+
{
2008+
size_t binary_count = 0;
2009+
size_t i;
2010+
2011+
if (parse_diff(state, ps) < 0)
2012+
return -1;
2013+
2014+
for (i = 0; i < state->file_diff_nr;) {
2015+
if (state->file_diff[i].binary && !state->file_diff[i].hunk_nr) {
2016+
binary_count++;
2017+
i++;
2018+
continue;
2019+
}
2020+
if ((i = patch_update_file(state, i)) == state->file_diff_nr)
2021+
break;
2022+
}
2023+
2024+
if (!state->cfg.auto_advance)
2025+
for (i = 0; i < state->file_diff_nr; i++)
2026+
apply_patch(state, state->file_diff + i);
2027+
2028+
if (state->file_diff_nr == 0)
2029+
err(state, _("No changes."));
2030+
else if (binary_count == state->file_diff_nr)
2031+
err(state, _("Only binary files changed."));
2032+
2033+
return 0;
2034+
}
2035+
19992036
int run_add_p(struct repository *r, enum add_p_mode mode,
20002037
struct interactive_options *opts, const char *revision,
20012038
const struct pathspec *ps)
20022039
{
20032040
struct add_p_state s = {
20042041
.r = r,
2042+
.index = r->index,
2043+
.index_file = r->index_file,
20052044
.answer = STRBUF_INIT,
20062045
.buf = STRBUF_INIT,
20072046
.plain = STRBUF_INIT,
20082047
.colored = STRBUF_INIT,
20092048
};
2010-
size_t i, binary_count = 0;
2049+
int ret;
20112050

20122051
interactive_config_init(&s.cfg, r, opts);
20132052

@@ -2040,30 +2079,90 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
20402079
if (repo_read_index(r) < 0 ||
20412080
(!s.mode->index_only &&
20422081
repo_refresh_and_write_index(r, REFRESH_QUIET, 0, 1,
2043-
NULL, NULL, NULL) < 0) ||
2044-
parse_diff(&s, ps) < 0) {
2045-
add_p_state_clear(&s);
2046-
return -1;
2082+
NULL, NULL, NULL) < 0)) {
2083+
ret = -1;
2084+
goto out;
20472085
}
20482086

2049-
for (i = 0; i < s.file_diff_nr;) {
2050-
if (s.file_diff[i].binary && !s.file_diff[i].hunk_nr) {
2051-
binary_count++;
2052-
i++;
2053-
continue;
2054-
}
2055-
if ((i = patch_update_file(&s, i)) == s.file_diff_nr)
2056-
break;
2057-
}
2058-
if (!s.cfg.auto_advance)
2059-
for (i = 0; i < s.file_diff_nr; i++)
2060-
apply_patch(&s, s.file_diff + i);
2087+
ret = run_add_p_common(&s, ps);
2088+
if (ret < 0)
2089+
goto out;
20612090

2062-
if (s.file_diff_nr == 0)
2063-
err(&s, _("No changes."));
2064-
else if (binary_count == s.file_diff_nr)
2065-
err(&s, _("Only binary files changed."));
2091+
ret = 0;
20662092

2093+
out:
20672094
add_p_state_clear(&s);
2068-
return 0;
2095+
return ret;
2096+
}
2097+
2098+
int run_add_p_index(struct repository *r,
2099+
struct index_state *index,
2100+
const char *index_file,
2101+
struct interactive_options *opts,
2102+
const char *revision,
2103+
const struct pathspec *ps)
2104+
{
2105+
struct patch_mode mode = {
2106+
.apply_args = { "--cached", NULL },
2107+
.apply_check_args = { "--cached", NULL },
2108+
.prompt_mode = {
2109+
N_("Stage mode change [y,n,q,a,d%s,?]? "),
2110+
N_("Stage deletion [y,n,q,a,d%s,?]? "),
2111+
N_("Stage addition [y,n,q,a,d%s,?]? "),
2112+
N_("Stage this hunk [y,n,q,a,d%s,?]? ")
2113+
},
2114+
.edit_hunk_hint = N_("If the patch applies cleanly, the edited hunk "
2115+
"will immediately be marked for staging."),
2116+
.help_patch_text =
2117+
N_("y - stage this hunk\n"
2118+
"n - do not stage this hunk\n"
2119+
"q - quit; do not stage this hunk or any of the remaining "
2120+
"ones\n"
2121+
"a - stage this hunk and all later hunks in the file\n"
2122+
"d - do not stage this hunk or any of the later hunks in "
2123+
"the file\n"),
2124+
.index_only = 1,
2125+
};
2126+
struct add_p_state s = {
2127+
.r = r,
2128+
.index = index,
2129+
.index_file = index_file,
2130+
.answer = STRBUF_INIT,
2131+
.buf = STRBUF_INIT,
2132+
.plain = STRBUF_INIT,
2133+
.colored = STRBUF_INIT,
2134+
.mode = &mode,
2135+
.revision = revision,
2136+
};
2137+
char parent_tree_oid[GIT_MAX_HEXSZ + 1];
2138+
struct commit *commit;
2139+
int ret;
2140+
2141+
interactive_config_init(&s.cfg, r, opts);
2142+
2143+
commit = lookup_commit_reference_by_name(revision);
2144+
if (!commit) {
2145+
err(&s, _("Revision does not refer to a commit"));
2146+
ret = -1;
2147+
goto out;
2148+
}
2149+
2150+
if (commit->parents)
2151+
oid_to_hex_r(parent_tree_oid, get_commit_tree_oid(commit->parents->item));
2152+
else
2153+
oid_to_hex_r(parent_tree_oid, r->hash_algo->empty_tree);
2154+
2155+
mode.diff_cmd[0] = "diff-tree";
2156+
mode.diff_cmd[1] = "-r";
2157+
mode.diff_cmd[2] = parent_tree_oid;
2158+
2159+
ret = run_add_p_common(&s, ps);
2160+
if (ret < 0)
2161+
goto out;
2162+
2163+
ret = 0;
2164+
2165+
out:
2166+
add_p_state_clear(&s);
2167+
return ret;
20692168
}

add-patch.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
#include "color.h"
55

6+
struct index_state;
67
struct pathspec;
78
struct repository;
89

@@ -56,4 +57,11 @@ int run_add_p(struct repository *r, enum add_p_mode mode,
5657
struct interactive_options *opts, const char *revision,
5758
const struct pathspec *ps);
5859

60+
int run_add_p_index(struct repository *r,
61+
struct index_state *index,
62+
const char *index_file,
63+
struct interactive_options *opts,
64+
const char *revision,
65+
const struct pathspec *ps);
66+
5967
#endif

0 commit comments

Comments
 (0)