Skip to content

Commit ac997db

Browse files
committed
Merge branch 'nd/diff-apply-ita'
"git diff" compares the index and the working tree. For paths added with intent-to-add bit, the command shows the full contents of them as added, but the paths themselves were not marked as new files. They are now shown as new by default. "git apply" learned the "--intent-to-add" option so that an otherwise working-tree-only application of a patch will add new paths to the index marked with the "intent-to-add" bit. * nd/diff-apply-ita: apply: add --intent-to-add t2203: add a test about "diff HEAD" case diff: turn --ita-invisible-in-index on by default diff: ignore --ita-[in]visible-in-index when diffing worktree-to-tree
2 parents a856e7d + cff5dc0 commit ac997db

File tree

7 files changed

+99
-20
lines changed

7 files changed

+99
-20
lines changed

Documentation/git-apply.txt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-apply - Apply a patch to files and/or to the index
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git apply' [--stat] [--numstat] [--summary] [--check] [--index] [--3way]
12+
'git apply' [--stat] [--numstat] [--summary] [--check] [--index | --intent-to-add] [--3way]
1313
[--apply] [--no-add] [--build-fake-ancestor=<file>] [-R | --reverse]
1414
[--allow-binary-replacement | --binary] [--reject] [-z]
1515
[-p<n>] [-C<n>] [--inaccurate-eof] [--recount] [--cached]
@@ -74,6 +74,14 @@ OPTIONS
7474
cached data, apply the patch, and store the result in the index
7575
without using the working tree. This implies `--index`.
7676

77+
--intent-to-add::
78+
When applying the patch only to the working tree, mark new
79+
files to be added to the index later (see `--intent-to-add`
80+
option in linkgit:git-add[1]). This option is ignored unless
81+
running in a Git repository and `--index` is not specified.
82+
Note that `--index` could be implied by other options such
83+
as `--cached` or `--3way`.
84+
7785
-3::
7886
--3way::
7987
When the patch does not apply cleanly, fall back on 3-way merge if

apply.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ int check_apply_state(struct apply_state *state, int force_apply)
141141
return error(_("--cached outside a repository"));
142142
state->check_index = 1;
143143
}
144+
if (state->ita_only && (state->check_index || is_not_gitdir))
145+
state->ita_only = 0;
144146
if (state->check_index)
145147
state->unsafe_paths = 0;
146148

@@ -4242,7 +4244,7 @@ static void patch_stats(struct apply_state *state, struct patch *patch)
42424244

42434245
static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
42444246
{
4245-
if (state->update_index) {
4247+
if (state->update_index && !state->ita_only) {
42464248
if (remove_file_from_cache(patch->old_name) < 0)
42474249
return error(_("unable to remove %s from index"), patch->old_name);
42484250
}
@@ -4265,15 +4267,15 @@ static int add_index_file(struct apply_state *state,
42654267
int namelen = strlen(path);
42664268
unsigned ce_size = cache_entry_size(namelen);
42674269

4268-
if (!state->update_index)
4269-
return 0;
4270-
42714270
ce = xcalloc(1, ce_size);
42724271
memcpy(ce->name, path, namelen);
42734272
ce->ce_mode = create_ce_mode(mode);
42744273
ce->ce_flags = create_ce_flags(0);
42754274
ce->ce_namelen = namelen;
4276-
if (S_ISGITLINK(mode)) {
4275+
if (state->ita_only) {
4276+
ce->ce_flags |= CE_INTENT_TO_ADD;
4277+
set_object_name_for_intent_to_add_entry(ce);
4278+
} else if (S_ISGITLINK(mode)) {
42774279
const char *s;
42784280

42794281
if (!skip_prefix(buf, "Subproject commit ", &s) ||
@@ -4465,8 +4467,9 @@ static int create_file(struct apply_state *state, struct patch *patch)
44654467

44664468
if (patch->conflicted_threeway)
44674469
return add_conflicted_stages_file(state, patch);
4468-
else
4470+
else if (state->update_index)
44694471
return add_index_file(state, path, mode, buf, size);
4472+
return 0;
44704473
}
44714474

44724475
/* phase zero is to remove, phase one is to create */
@@ -4686,7 +4689,7 @@ static int apply_patch(struct apply_state *state,
46864689
if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
46874690
state->apply = 0;
46884691

4689-
state->update_index = state->check_index && state->apply;
4692+
state->update_index = (state->check_index || state->ita_only) && state->apply;
46904693
if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
46914694
if (state->index_file)
46924695
hold_lock_file_for_update(&state->lock_file,
@@ -4941,6 +4944,8 @@ int apply_parse_options(int argc, const char **argv,
49414944
N_("instead of applying the patch, see if the patch is applicable")),
49424945
OPT_BOOL(0, "index", &state->check_index,
49434946
N_("make sure the patch is applicable to the current index")),
4947+
OPT_BOOL('N', "intent-to-add", &state->ita_only,
4948+
N_("mark new files with `git add --intent-to-add`")),
49444949
OPT_BOOL(0, "cached", &state->cached,
49454950
N_("apply a patch without touching the working tree")),
49464951
OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,

apply.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct apply_state {
4545
int check; /* preimage must match working tree, don't actually apply */
4646
int check_index; /* preimage must match the indexed version */
4747
int update_index; /* check_index && apply */
48+
int ita_only; /* add intent-to-add entries to the index */
4849

4950
/* These control cosmetic aspect of the output */
5051
int diffstat; /* just show a diffstat, and don't actually apply */

builtin/diff.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,13 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
352352
rev.diffopt.flags.allow_external = 1;
353353
rev.diffopt.flags.allow_textconv = 1;
354354

355+
/*
356+
* Default to intent-to-add entries invisible in the
357+
* index. This makes them show up as new files in diff-files
358+
* and not at all in diff-cached.
359+
*/
360+
rev.diffopt.ita_invisible_in_index = 1;
361+
355362
if (nongit)
356363
die(_("Not a git repository"));
357364
argc = setup_revisions(argc, argv, &rev, NULL);

diff-lib.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -389,8 +389,12 @@ static void do_oneway_diff(struct unpack_trees_options *o,
389389
struct rev_info *revs = o->unpack_data;
390390
int match_missing, cached;
391391

392-
/* i-t-a entries do not actually exist in the index */
393-
if (revs->diffopt.ita_invisible_in_index &&
392+
/*
393+
* i-t-a entries do not actually exist in the index (if we're
394+
* looking at its content)
395+
*/
396+
if (o->index_only &&
397+
revs->diffopt.ita_invisible_in_index &&
394398
idx && ce_intent_to_add(idx)) {
395399
idx = NULL;
396400
if (!tree)

t/t2203-add-intent.sh

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,7 @@ test_expect_success 'i-t-a entry is simply ignored' '
7070
git commit -m second &&
7171
test $(git ls-tree HEAD -- nitfol | wc -l) = 0 &&
7272
test $(git diff --name-only HEAD -- nitfol | wc -l) = 1 &&
73-
test $(git diff --name-only --ita-invisible-in-index HEAD -- nitfol | wc -l) = 0 &&
74-
test $(git diff --name-only --ita-invisible-in-index -- nitfol | wc -l) = 1
73+
test $(git diff --name-only -- nitfol | wc -l) = 1
7574
'
7675

7776
test_expect_success 'can commit with an unrelated i-t-a entry in index' '
@@ -99,13 +98,13 @@ test_expect_success 'cache-tree invalidates i-t-a paths' '
9998
10099
: >dir/bar &&
101100
git add -N dir/bar &&
102-
git diff --cached --name-only >actual &&
101+
git diff --name-only >actual &&
103102
echo dir/bar >expect &&
104103
test_cmp expect actual &&
105104
106105
git write-tree >/dev/null &&
107106
108-
git diff --cached --name-only >actual &&
107+
git diff --name-only >actual &&
109108
echo dir/bar >expect &&
110109
test_cmp expect actual
111110
'
@@ -186,7 +185,19 @@ test_expect_success 'rename detection finds the right names' '
186185
cat >expected.3 <<-EOF &&
187186
2 .R N... 100644 100644 100644 $hash $hash R100 third first
188187
EOF
189-
test_cmp expected.3 actual.3
188+
test_cmp expected.3 actual.3 &&
189+
190+
git diff --stat >actual.4 &&
191+
cat >expected.4 <<-EOF &&
192+
first => third | 0
193+
1 file changed, 0 insertions(+), 0 deletions(-)
194+
EOF
195+
test_cmp expected.4 actual.4 &&
196+
197+
git diff --cached --stat >actual.5 &&
198+
: >expected.5 &&
199+
test_cmp expected.5 actual.5
200+
190201
)
191202
'
192203

@@ -222,5 +233,46 @@ test_expect_success 'double rename detection in status' '
222233
)
223234
'
224235

225-
test_done
236+
test_expect_success 'diff-files/diff-cached shows ita as new/not-new files' '
237+
git reset --hard &&
238+
echo new >new-ita &&
239+
git add -N new-ita &&
240+
git diff --summary >actual &&
241+
echo " create mode 100644 new-ita" >expected &&
242+
test_cmp expected actual &&
243+
git diff --cached --summary >actual2 &&
244+
: >expected2 &&
245+
test_cmp expected2 actual2
246+
'
247+
226248

249+
test_expect_success '"diff HEAD" includes ita as new files' '
250+
git reset --hard &&
251+
echo new >new-ita &&
252+
git add -N new-ita &&
253+
git diff HEAD >actual &&
254+
cat >expected <<-\EOF &&
255+
diff --git a/new-ita b/new-ita
256+
new file mode 100644
257+
index 0000000..3e75765
258+
--- /dev/null
259+
+++ b/new-ita
260+
@@ -0,0 +1 @@
261+
+new
262+
EOF
263+
test_cmp expected actual
264+
'
265+
266+
test_expect_success 'apply --intent-to-add' '
267+
git reset --hard &&
268+
echo new >new-ita &&
269+
git add -N new-ita &&
270+
git diff >expected &&
271+
grep "new file" expected &&
272+
git reset --hard &&
273+
git apply --intent-to-add expected &&
274+
git diff >actual &&
275+
test_cmp expected actual
276+
'
277+
278+
test_done

t/t4011-diff-symlink.sh

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,13 @@ test_expect_success SYMLINKS 'setup symlinks with attributes' '
139139
test_expect_success SYMLINKS 'symlinks do not respect userdiff config by path' '
140140
cat >expect <<-\EOF &&
141141
diff --git a/file.bin b/file.bin
142-
index e69de29..d95f3ad 100644
143-
Binary files a/file.bin and b/file.bin differ
142+
new file mode 100644
143+
index 0000000..d95f3ad
144+
Binary files /dev/null and b/file.bin differ
144145
diff --git a/link.bin b/link.bin
145-
index e69de29..dce41ec 120000
146-
--- a/link.bin
146+
new file mode 120000
147+
index 0000000..dce41ec
148+
--- /dev/null
147149
+++ b/link.bin
148150
@@ -0,0 +1 @@
149151
+file.bin

0 commit comments

Comments
 (0)