Skip to content

Commit a3c76f2

Browse files
committed
Merge branch 'jc/add-ita'
* jc/add-ita: git-add --intent-to-add (-N)
2 parents d5c5274 + 3942581 commit a3c76f2

File tree

4 files changed

+65
-6
lines changed

4 files changed

+65
-6
lines changed

builtin-add.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ static const char ignore_error[] =
166166
"The following paths are ignored by one of your .gitignore files:\n";
167167

168168
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
169-
static int ignore_add_errors, addremove;
169+
static int ignore_add_errors, addremove, intent_to_add;
170170

171171
static struct option builtin_add_options[] = {
172172
OPT__DRY_RUN(&show_only),
@@ -176,6 +176,7 @@ static struct option builtin_add_options[] = {
176176
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
177177
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
178178
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
179+
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
179180
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
180181
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
181182
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
@@ -246,6 +247,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
246247

247248
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
248249
(show_only ? ADD_CACHE_PRETEND : 0) |
250+
(intent_to_add ? ADD_CACHE_INTENT : 0) |
249251
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
250252
(!(addremove || take_worktree_changes)
251253
? ADD_CACHE_IGNORE_REMOVAL : 0));

cache.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
377377
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
378378
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
379379
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
380+
#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
380381
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
381382
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
382383
extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
@@ -386,6 +387,7 @@ extern int remove_file_from_index(struct index_state *, const char *path);
386387
#define ADD_CACHE_PRETEND 2
387388
#define ADD_CACHE_IGNORE_ERRORS 4
388389
#define ADD_CACHE_IGNORE_REMOVAL 8
390+
#define ADD_CACHE_INTENT 16
389391
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
390392
extern int add_file_to_index(struct index_state *, const char *path, int flags);
391393
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);

read-cache.c

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "diff.h"
1414
#include "diffcore.h"
1515
#include "revision.h"
16+
#include "blob.h"
1617

1718
/* Index extensions.
1819
*
@@ -511,6 +512,14 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
511512
return new;
512513
}
513514

515+
static void record_intent_to_add(struct cache_entry *ce)
516+
{
517+
unsigned char sha1[20];
518+
if (write_sha1_file("", 0, blob_type, sha1))
519+
die("cannot create an empty blob in the object database");
520+
hashcpy(ce->sha1, sha1);
521+
}
522+
514523
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
515524
{
516525
int size, namelen, was_same;
@@ -519,6 +528,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
519528
unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
520529
int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
521530
int pretend = flags & ADD_CACHE_PRETEND;
531+
int intent_only = flags & ADD_CACHE_INTENT;
532+
int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
533+
(intent_only ? ADD_CACHE_NEW_ONLY : 0));
522534

523535
if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
524536
return error("%s: can only add regular files, symbolic links or git-directories", path);
@@ -532,7 +544,8 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
532544
ce = xcalloc(1, size);
533545
memcpy(ce->name, path, namelen);
534546
ce->ce_flags = namelen;
535-
fill_stat_cache_info(ce, st);
547+
if (!intent_only)
548+
fill_stat_cache_info(ce, st);
536549

537550
if (trust_executable_bit && has_symlinks)
538551
ce->ce_mode = create_ce_mode(st_mode);
@@ -555,8 +568,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
555568
alias->ce_flags |= CE_ADDED;
556569
return 0;
557570
}
558-
if (index_path(ce->sha1, path, st, 1))
559-
return error("unable to index file %s", path);
571+
if (!intent_only) {
572+
if (index_path(ce->sha1, path, st, 1))
573+
return error("unable to index file %s", path);
574+
} else
575+
record_intent_to_add(ce);
576+
560577
if (ignore_case && alias && different_name(ce, alias))
561578
ce = create_alias_ce(ce, alias);
562579
ce->ce_flags |= CE_ADDED;
@@ -569,7 +586,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
569586

570587
if (pretend)
571588
;
572-
else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
589+
else if (add_index_entry(istate, ce, add_option))
573590
return error("unable to add %s to index",path);
574591
if (verbose && !was_same)
575592
printf("add '%s'\n", path);
@@ -848,13 +865,15 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
848865
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
849866
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
850867
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
868+
int new_only = option & ADD_CACHE_NEW_ONLY;
851869

852870
cache_tree_invalidate_path(istate->cache_tree, ce->name);
853871
pos = index_name_pos(istate, ce->name, ce->ce_flags);
854872

855873
/* existing match? Just replace it. */
856874
if (pos >= 0) {
857-
replace_index_entry(istate, pos, ce);
875+
if (!new_only)
876+
replace_index_entry(istate, pos, ce);
858877
return 0;
859878
}
860879
pos = -pos-1;

t/t2203-add-intent.sh

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#!/bin/sh
2+
3+
test_description='Intent to add'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success 'intent to add' '
8+
echo hello >file &&
9+
echo hello >elif &&
10+
git add -N file &&
11+
git add elif
12+
'
13+
14+
test_expect_success 'check result of "add -N"' '
15+
git ls-files -s file >actual &&
16+
empty=$(git hash-object --stdin </dev/null) &&
17+
echo "100644 $empty 0 file" >expect &&
18+
test_cmp expect actual
19+
'
20+
21+
test_expect_success 'intent to add is just an ordinary empty blob' '
22+
git add -u &&
23+
git ls-files -s file >actual &&
24+
git ls-files -s elif | sed -e "s/elif/file/" >expect &&
25+
test_cmp expect actual
26+
'
27+
28+
test_expect_success 'intent to add does not clobber existing paths' '
29+
git add -N file elif &&
30+
empty=$(git hash-object --stdin </dev/null) &&
31+
git ls-files -s >actual &&
32+
! grep "$empty" actual
33+
'
34+
35+
test_done
36+

0 commit comments

Comments
 (0)