mirror of
https://github.com/git/git
synced 2024-08-27 19:49:21 +00:00
Merge branch 'jc/add-ita'
* jc/add-ita: git-add --intent-to-add (-N)
This commit is contained in:
commit
a3c76f2858
|
@ -166,7 +166,7 @@ static const char ignore_error[] =
|
|||
"The following paths are ignored by one of your .gitignore files:\n";
|
||||
|
||||
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
||||
static int ignore_add_errors, addremove;
|
||||
static int ignore_add_errors, addremove, intent_to_add;
|
||||
|
||||
static struct option builtin_add_options[] = {
|
||||
OPT__DRY_RUN(&show_only),
|
||||
|
@ -176,6 +176,7 @@ static struct option builtin_add_options[] = {
|
|||
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
||||
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
|
||||
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
|
||||
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
|
||||
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
|
||||
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
||||
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)
|
|||
|
||||
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
|
||||
(show_only ? ADD_CACHE_PRETEND : 0) |
|
||||
(intent_to_add ? ADD_CACHE_INTENT : 0) |
|
||||
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
||||
(!(addremove || take_worktree_changes)
|
||||
? ADD_CACHE_IGNORE_REMOVAL : 0));
|
||||
|
|
2
cache.h
2
cache.h
|
@ -377,6 +377,7 @@ extern int index_name_pos(const struct index_state *, const char *name, int name
|
|||
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
|
||||
#define ADD_CACHE_SKIP_DFCHECK 4 /* Ok to skip DF conflict checks */
|
||||
#define ADD_CACHE_JUST_APPEND 8 /* Append only; tree.c::read_tree() */
|
||||
#define ADD_CACHE_NEW_ONLY 16 /* Do not replace existing ones */
|
||||
extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
|
||||
extern struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
|
||||
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);
|
|||
#define ADD_CACHE_PRETEND 2
|
||||
#define ADD_CACHE_IGNORE_ERRORS 4
|
||||
#define ADD_CACHE_IGNORE_REMOVAL 8
|
||||
#define ADD_CACHE_INTENT 16
|
||||
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
|
||||
extern int add_file_to_index(struct index_state *, const char *path, int flags);
|
||||
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
|
||||
|
|
29
read-cache.c
29
read-cache.c
|
@ -13,6 +13,7 @@
|
|||
#include "diff.h"
|
||||
#include "diffcore.h"
|
||||
#include "revision.h"
|
||||
#include "blob.h"
|
||||
|
||||
/* Index extensions.
|
||||
*
|
||||
|
@ -511,6 +512,14 @@ static struct cache_entry *create_alias_ce(struct cache_entry *ce, struct cache_
|
|||
return new;
|
||||
}
|
||||
|
||||
static void record_intent_to_add(struct cache_entry *ce)
|
||||
{
|
||||
unsigned char sha1[20];
|
||||
if (write_sha1_file("", 0, blob_type, sha1))
|
||||
die("cannot create an empty blob in the object database");
|
||||
hashcpy(ce->sha1, sha1);
|
||||
}
|
||||
|
||||
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
|
||||
{
|
||||
int size, namelen, was_same;
|
||||
|
@ -519,6 +528,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
|
|||
unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
|
||||
int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
|
||||
int pretend = flags & ADD_CACHE_PRETEND;
|
||||
int intent_only = flags & ADD_CACHE_INTENT;
|
||||
int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
|
||||
(intent_only ? ADD_CACHE_NEW_ONLY : 0));
|
||||
|
||||
if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
|
||||
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,
|
|||
ce = xcalloc(1, size);
|
||||
memcpy(ce->name, path, namelen);
|
||||
ce->ce_flags = namelen;
|
||||
fill_stat_cache_info(ce, st);
|
||||
if (!intent_only)
|
||||
fill_stat_cache_info(ce, st);
|
||||
|
||||
if (trust_executable_bit && has_symlinks)
|
||||
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,
|
|||
alias->ce_flags |= CE_ADDED;
|
||||
return 0;
|
||||
}
|
||||
if (index_path(ce->sha1, path, st, 1))
|
||||
return error("unable to index file %s", path);
|
||||
if (!intent_only) {
|
||||
if (index_path(ce->sha1, path, st, 1))
|
||||
return error("unable to index file %s", path);
|
||||
} else
|
||||
record_intent_to_add(ce);
|
||||
|
||||
if (ignore_case && alias && different_name(ce, alias))
|
||||
ce = create_alias_ce(ce, alias);
|
||||
ce->ce_flags |= CE_ADDED;
|
||||
|
@ -569,7 +586,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
|
|||
|
||||
if (pretend)
|
||||
;
|
||||
else if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
|
||||
else if (add_index_entry(istate, ce, add_option))
|
||||
return error("unable to add %s to index",path);
|
||||
if (verbose && !was_same)
|
||||
printf("add '%s'\n", path);
|
||||
|
@ -848,13 +865,15 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
|
|||
int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
|
||||
int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
|
||||
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
|
||||
int new_only = option & ADD_CACHE_NEW_ONLY;
|
||||
|
||||
cache_tree_invalidate_path(istate->cache_tree, ce->name);
|
||||
pos = index_name_pos(istate, ce->name, ce->ce_flags);
|
||||
|
||||
/* existing match? Just replace it. */
|
||||
if (pos >= 0) {
|
||||
replace_index_entry(istate, pos, ce);
|
||||
if (!new_only)
|
||||
replace_index_entry(istate, pos, ce);
|
||||
return 0;
|
||||
}
|
||||
pos = -pos-1;
|
||||
|
|
36
t/t2203-add-intent.sh
Executable file
36
t/t2203-add-intent.sh
Executable file
|
@ -0,0 +1,36 @@
|
|||
#!/bin/sh
|
||||
|
||||
test_description='Intent to add'
|
||||
|
||||
. ./test-lib.sh
|
||||
|
||||
test_expect_success 'intent to add' '
|
||||
echo hello >file &&
|
||||
echo hello >elif &&
|
||||
git add -N file &&
|
||||
git add elif
|
||||
'
|
||||
|
||||
test_expect_success 'check result of "add -N"' '
|
||||
git ls-files -s file >actual &&
|
||||
empty=$(git hash-object --stdin </dev/null) &&
|
||||
echo "100644 $empty 0 file" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'intent to add is just an ordinary empty blob' '
|
||||
git add -u &&
|
||||
git ls-files -s file >actual &&
|
||||
git ls-files -s elif | sed -e "s/elif/file/" >expect &&
|
||||
test_cmp expect actual
|
||||
'
|
||||
|
||||
test_expect_success 'intent to add does not clobber existing paths' '
|
||||
git add -N file elif &&
|
||||
empty=$(git hash-object --stdin </dev/null) &&
|
||||
git ls-files -s >actual &&
|
||||
! grep "$empty" actual
|
||||
'
|
||||
|
||||
test_done
|
||||
|
Loading…
Reference in a new issue