Skip to content

Commit 610d55a

Browse files
tgummerergitster
authored andcommitted
add: modify already added files when --chmod is given
When the chmod option was added to git add, it was hooked up to the diff machinery, meaning that it only works when the version in the index differs from the version on disk. As the option was supposed to mirror the chmod option in update-index, which always changes the mode in the index, regardless of the status of the file, make sure the option behaves the same way in git add. Signed-off-by: Thomas Gummerer <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d9d7096 commit 610d55a

File tree

6 files changed

+91
-34
lines changed

6 files changed

+91
-34
lines changed

builtin/add.c

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,25 @@ static int patch_interactive, add_interactive, edit_interactive;
2626
static int take_worktree_changes;
2727

2828
struct update_callback_data {
29-
int flags, force_mode;
29+
int flags;
3030
int add_errors;
3131
};
3232

33+
static void chmod_pathspec(struct pathspec *pathspec, int force_mode)
34+
{
35+
int i;
36+
37+
for (i = 0; i < active_nr; i++) {
38+
struct cache_entry *ce = active_cache[i];
39+
40+
if (pathspec && !ce_path_match(ce, pathspec, NULL))
41+
continue;
42+
43+
if (chmod_cache_entry(ce, force_mode) < 0)
44+
fprintf(stderr, "cannot chmod '%s'", ce->name);
45+
}
46+
}
47+
3348
static int fix_unmerged_status(struct diff_filepair *p,
3449
struct update_callback_data *data)
3550
{
@@ -65,8 +80,7 @@ static void update_callback(struct diff_queue_struct *q,
6580
die(_("unexpected diff status %c"), p->status);
6681
case DIFF_STATUS_MODIFIED:
6782
case DIFF_STATUS_TYPE_CHANGED:
68-
if (add_file_to_index(&the_index, path,
69-
data->flags, data->force_mode)) {
83+
if (add_file_to_index(&the_index, path, data->flags)) {
7084
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
7185
die(_("updating files failed"));
7286
data->add_errors++;
@@ -84,15 +98,14 @@ static void update_callback(struct diff_queue_struct *q,
8498
}
8599
}
86100

87-
int add_files_to_cache(const char *prefix, const struct pathspec *pathspec,
88-
int flags, int force_mode)
101+
int add_files_to_cache(const char *prefix,
102+
const struct pathspec *pathspec, int flags)
89103
{
90104
struct update_callback_data data;
91105
struct rev_info rev;
92106

93107
memset(&data, 0, sizeof(data));
94108
data.flags = flags;
95-
data.force_mode = force_mode;
96109

97110
init_revisions(&rev, prefix);
98111
setup_revisions(0, NULL, &rev, NULL);
@@ -281,7 +294,7 @@ static int add_config(const char *var, const char *value, void *cb)
281294
return git_default_config(var, value, cb);
282295
}
283296

284-
static int add_files(struct dir_struct *dir, int flags, int force_mode)
297+
static int add_files(struct dir_struct *dir, int flags)
285298
{
286299
int i, exit_status = 0;
287300

@@ -294,8 +307,7 @@ static int add_files(struct dir_struct *dir, int flags, int force_mode)
294307
}
295308

296309
for (i = 0; i < dir->nr; i++)
297-
if (add_file_to_index(&the_index, dir->entries[i]->name,
298-
flags, force_mode)) {
310+
if (add_file_to_index(&the_index, dir->entries[i]->name, flags)) {
299311
if (!ignore_add_errors)
300312
die(_("adding files failed"));
301313
exit_status = 1;
@@ -308,7 +320,7 @@ int cmd_add(int argc, const char **argv, const char *prefix)
308320
int exit_status = 0;
309321
struct pathspec pathspec;
310322
struct dir_struct dir;
311-
int flags, force_mode;
323+
int flags;
312324
int add_new_files;
313325
int require_pathspec;
314326
char *seen = NULL;
@@ -342,13 +354,8 @@ int cmd_add(int argc, const char **argv, const char *prefix)
342354
if (!show_only && ignore_missing)
343355
die(_("Option --ignore-missing can only be used together with --dry-run"));
344356

345-
if (!chmod_arg)
346-
force_mode = 0;
347-
else if (!strcmp(chmod_arg, "-x"))
348-
force_mode = 0666;
349-
else if (!strcmp(chmod_arg, "+x"))
350-
force_mode = 0777;
351-
else
357+
if (chmod_arg && ((chmod_arg[0] != '-' && chmod_arg[0] != '+') ||
358+
chmod_arg[1] != 'x' || chmod_arg[2]))
352359
die(_("--chmod param '%s' must be either -x or +x"), chmod_arg);
353360

354361
add_new_files = !take_worktree_changes && !refresh_only;
@@ -441,11 +448,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
441448

442449
plug_bulk_checkin();
443450

444-
exit_status |= add_files_to_cache(prefix, &pathspec, flags, force_mode);
451+
exit_status |= add_files_to_cache(prefix, &pathspec, flags);
445452

446453
if (add_new_files)
447-
exit_status |= add_files(&dir, flags, force_mode);
454+
exit_status |= add_files(&dir, flags);
448455

456+
if (chmod_arg && pathspec.nr)
457+
chmod_pathspec(&pathspec, chmod_arg[0]);
449458
unplug_bulk_checkin();
450459

451460
finish:

builtin/checkout.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
548548
* entries in the index.
549549
*/
550550

551-
add_files_to_cache(NULL, NULL, 0, 0);
551+
add_files_to_cache(NULL, NULL, 0);
552552
/*
553553
* NEEDSWORK: carrying over local changes
554554
* when branches have different end-of-line

builtin/commit.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ static const char *prepare_index(int argc, const char **argv, const char *prefix
386386
*/
387387
if (all || (also && pathspec.nr)) {
388388
hold_locked_index(&index_lock, 1);
389-
add_files_to_cache(also ? prefix : NULL, &pathspec, 0, 0);
389+
add_files_to_cache(also ? prefix : NULL, &pathspec, 0);
390390
refresh_cache_or_die(refresh_flags);
391391
update_main_cache_tree(WRITE_TREE_SILENT);
392392
if (write_locked_index(&the_index, &index_lock, CLOSE_LOCK))

cache.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -367,8 +367,8 @@ extern void free_name_hash(struct index_state *istate);
367367
#define rename_cache_entry_at(pos, new_name) rename_index_entry_at(&the_index, (pos), (new_name))
368368
#define remove_cache_entry_at(pos) remove_index_entry_at(&the_index, (pos))
369369
#define remove_file_from_cache(path) remove_file_from_index(&the_index, (path))
370-
#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags), 0)
371-
#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags), 0)
370+
#define add_to_cache(path, st, flags) add_to_index(&the_index, (path), (st), (flags))
371+
#define add_file_to_cache(path, flags) add_file_to_index(&the_index, (path), (flags))
372372
#define chmod_cache_entry(ce, flip) chmod_index_entry(&the_index, (ce), (flip))
373373
#define refresh_cache(flags) refresh_index(&the_index, (flags), NULL, NULL, NULL)
374374
#define ce_match_stat(ce, st, options) ie_match_stat(&the_index, (ce), (st), (options))
@@ -582,8 +582,8 @@ extern int remove_file_from_index(struct index_state *, const char *path);
582582
#define ADD_CACHE_IGNORE_ERRORS 4
583583
#define ADD_CACHE_IGNORE_REMOVAL 8
584584
#define ADD_CACHE_INTENT 16
585-
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags, int force_mode);
586-
extern int add_file_to_index(struct index_state *, const char *path, int flags, int force_mode);
585+
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
586+
extern int add_file_to_index(struct index_state *, const char *path, int flags);
587587
extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
588588
extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
589589
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
@@ -1774,7 +1774,7 @@ void packet_trace_identity(const char *prog);
17741774
* return 0 if success, 1 - if addition of a file failed and
17751775
* ADD_FILES_IGNORE_ERRORS was specified in flags
17761776
*/
1777-
int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags, int force_mode);
1777+
int add_files_to_cache(const char *prefix, const struct pathspec *pathspec, int flags);
17781778

17791779
/* diff.c */
17801780
extern int diff_auto_refresh_index;

read-cache.c

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
630630
hashcpy(ce->sha1, sha1);
631631
}
632632

633-
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags, int force_mode)
633+
int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
634634
{
635635
int size, namelen, was_same;
636636
mode_t st_mode = st->st_mode;
@@ -659,11 +659,10 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
659659
else
660660
ce->ce_flags |= CE_INTENT_TO_ADD;
661661

662-
if (S_ISREG(st_mode) && force_mode)
663-
ce->ce_mode = create_ce_mode(force_mode);
664-
else if (trust_executable_bit && has_symlinks)
662+
663+
if (trust_executable_bit && has_symlinks) {
665664
ce->ce_mode = create_ce_mode(st_mode);
666-
else {
665+
} else {
667666
/* If there is an existing entry, pick the mode bits and type
668667
* from it, otherwise assume unexecutable regular file.
669668
*/
@@ -722,13 +721,12 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
722721
return 0;
723722
}
724723

725-
int add_file_to_index(struct index_state *istate, const char *path,
726-
int flags, int force_mode)
724+
int add_file_to_index(struct index_state *istate, const char *path, int flags)
727725
{
728726
struct stat st;
729727
if (lstat(path, &st))
730728
die_errno("unable to stat '%s'", path);
731-
return add_to_index(istate, path, &st, flags, force_mode);
729+
return add_to_index(istate, path, &st, flags);
732730
}
733731

734732
struct cache_entry *make_cache_entry(unsigned int mode,

t/t3700-add.sh

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,4 +349,54 @@ test_expect_success POSIXPERM,SYMLINKS 'git add --chmod=+x with symlinks' '
349349
test_mode_in_index 100755 foo2
350350
'
351351

352+
test_expect_success 'git add --chmod=[+-]x changes index with already added file' '
353+
echo foo >foo3 &&
354+
git add foo3 &&
355+
git add --chmod=+x foo3 &&
356+
test_mode_in_index 100755 foo3 &&
357+
echo foo >xfoo3 &&
358+
chmod 755 xfoo3 &&
359+
git add xfoo3 &&
360+
git add --chmod=-x xfoo3 &&
361+
test_mode_in_index 100644 xfoo3
362+
'
363+
364+
test_expect_success 'file status is changed after git add --chmod=+x' '
365+
echo "AM foo4" >expected &&
366+
echo foo >foo4 &&
367+
git add foo4 &&
368+
git add --chmod=+x foo4 &&
369+
git status -s foo4 >actual &&
370+
test_cmp expected actual
371+
'
372+
373+
test_expect_success 'no file status change if no pathspec is given' '
374+
>foo5 &&
375+
>foo6 &&
376+
git add foo5 foo6 &&
377+
git add --chmod=+x &&
378+
test_mode_in_index 100644 foo5 &&
379+
test_mode_in_index 100644 foo6
380+
'
381+
382+
test_expect_success 'no file status change if no pathspec is given in subdir' '
383+
mkdir sub &&
384+
(
385+
cd sub &&
386+
>sub-foo1 &&
387+
>sub-foo2 &&
388+
git add . &&
389+
git add --chmod=+x &&
390+
test_mode_in_index 100644 sub-foo1 &&
391+
test_mode_in_index 100644 sub-foo2
392+
)
393+
'
394+
395+
test_expect_success 'all statuses changed in folder if . is given' '
396+
git add --chmod=+x . &&
397+
test $(git ls-files --stage | grep ^100644 | wc -l) -eq 0 &&
398+
git add --chmod=-x . &&
399+
test $(git ls-files --stage | grep ^100755 | wc -l) -eq 0
400+
'
401+
352402
test_done

0 commit comments

Comments
 (0)