git-commit-vandalism/builtin/add.c

452 lines
12 KiB
C
Raw Normal View History

/*
* "git add" builtin command
*
* Copyright (C) 2006 Linus Torvalds
*/
#include "cache.h"
#include "builtin.h"
#include "lockfile.h"
#include "dir.h"
#include "pathspec.h"
git-add --interactive A script to be driven when the user says "git add --interactive" is introduced. When it is run, first it runs its internal 'status' command to show the current status, and then goes into its internactive command loop. The command loop shows the list of subcommands available, and gives a prompt "What now> ". In general, when the prompt ends with a single '>', you can pick only one of the choices given and type return, like this: *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now> 1 You also could say "s" or "sta" or "status" above as long as the choice is unique. The main command loop has 6 subcommands (plus help and quit). * 'status' shows the change between HEAD and index (i.e. what will be committed if you say "git commit"), and between index and working tree files (i.e. what you could stage further before "git commit" using "git-add") for each path. A sample output looks like this: staged unstaged path 1: binary nothing foo.png 2: +403/-35 +1/-1 git-add--interactive.perl It shows that foo.png has differences from HEAD (but that is binary so line count cannot be shown) and there is no difference between indexed copy and the working tree version (if the working tree version were also different, 'binary' would have been shown in place of 'nothing'). The other file, git-add--interactive.perl, has 403 lines added and 35 lines deleted if you commit what is in the index, but working tree file has further modifications (one addition and one deletion). * 'update' shows the status information and gives prompt "Update>>". When the prompt ends with double '>>', you can make more than one selection, concatenated with whitespace or comma. Also you can say ranges. E.g. "2-5 7,9" to choose 2,3,4,5,7,9 from the list. You can say '*' to choose everything. What you chose are then highlighted with '*', like this: staged unstaged path 1: binary nothing foo.png * 2: +403/-35 +1/-1 git-add--interactive.perl To remove selection, prefix the input with - like this: Update>> -2 After making the selection, answer with an empty line to stage the contents of working tree files for selected paths in the index. * 'revert' has a very similar UI to 'update', and the staged information for selected paths are reverted to that of the HEAD version. Reverting new paths makes them untracked. * 'add untracked' has a very similar UI to 'update' and 'revert', and lets you add untracked paths to the index. * 'patch' lets you choose one path out of 'status' like selection. After choosing the path, it presents diff between the index and the working tree file and asks you if you want to stage the change of each hunk. You can say: y - add the change from that hunk to index n - do not add the change from that hunk to index a - add the change from that hunk and all the rest to index d - do not the change from that hunk nor any of the rest to index j - do not decide on this hunk now, and view the next undecided hunk J - do not decide on this hunk now, and view the next hunk k - do not decide on this hunk now, and view the previous undecided hunk K - do not decide on this hunk now, and view the previous hunk After deciding the fate for all hunks, if there is any hunk that was chosen, the index is updated with the selected hunks. * 'diff' lets you review what will be committed (i.e. between HEAD and index). This is still rough, but does everything except a few things I think are needed. * 'patch' should be able to allow splitting a hunk into multiple hunks. * 'patch' does not adjust the line offsets @@ -k,l +m,n @@ in the hunk header. This does not have major problem in practice, but it _should_ do the adjustment. * It does not have any explicit support for a merge in progress; it may not work at all. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-12-11 05:55:50 +01:00
#include "exec_cmd.h"
#include "cache-tree.h"
#include "run-command.h"
#include "parse-options.h"
#include "diff.h"
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
#include "diffcore.h"
#include "revision.h"
#include "bulk-checkin.h"
#include "argv-array.h"
static const char * const builtin_add_usage[] = {
N_("git add [<options>] [--] <pathspec>..."),
NULL
};
static int patch_interactive, add_interactive, edit_interactive;
static int take_worktree_changes;
struct update_callback_data {
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
int flags;
int add_errors;
};
Fix "add -u" that sometimes fails to resolve unmerged paths "git add -u" updates the index with the updated contents from the working tree by internally running "diff-files" to grab the set of paths that are different from the index. Then it updates the index entries for the paths that are modified in the working tree, and deletes the index entries for the paths that are deleted in the working tree. It ignored the output from the diff-files that indicated that a path is unmerged. For these paths, it instead relied on the fact that an unmerged path is followed by the result of comparison between stage #2 (ours) and the working tree, and used that to update or delete such a path when it is used to record the resolution of a conflict. As the result, when a path did not have stage #2 (e.g. "we deleted while the other side added"), these unmerged stages were left behind, instead of recording what the user resolved in the working tree. Since we recently fixed "diff-files" to indicate if the corresponding path exists on the working tree for an unmerged path, we do not have to rely on the comparison with stage #2 anymore. We can instead tell the diff-files not to compare with higher stages, and use the unmerged output to update the index to reflect the state of the working tree. The changes to the test vector in t2200 illustrates the nature of the bug and the fix. The test expected stage #1 and #3 entries be left behind, but it was codifying the buggy behaviour. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-04-21 03:11:19 +02:00
static int fix_unmerged_status(struct diff_filepair *p,
struct update_callback_data *data)
{
if (p->status != DIFF_STATUS_UNMERGED)
return p->status;
if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL) && !p->two->mode)
/*
* This is not an explicit add request, and the
* path is missing from the working tree (deleted)
*/
return DIFF_STATUS_DELETED;
else
/*
* Either an explicit add request, or path exists
* in the working tree. An attempt to explicitly
* add a path that does not exist in the working tree
* will be caught as an error by the caller immediately.
*/
return DIFF_STATUS_MODIFIED;
}
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
static void update_callback(struct diff_queue_struct *q,
struct diff_options *opt, void *cbdata)
{
int i;
struct update_callback_data *data = cbdata;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];
const char *path = p->one->path;
Fix "add -u" that sometimes fails to resolve unmerged paths "git add -u" updates the index with the updated contents from the working tree by internally running "diff-files" to grab the set of paths that are different from the index. Then it updates the index entries for the paths that are modified in the working tree, and deletes the index entries for the paths that are deleted in the working tree. It ignored the output from the diff-files that indicated that a path is unmerged. For these paths, it instead relied on the fact that an unmerged path is followed by the result of comparison between stage #2 (ours) and the working tree, and used that to update or delete such a path when it is used to record the resolution of a conflict. As the result, when a path did not have stage #2 (e.g. "we deleted while the other side added"), these unmerged stages were left behind, instead of recording what the user resolved in the working tree. Since we recently fixed "diff-files" to indicate if the corresponding path exists on the working tree for an unmerged path, we do not have to rely on the comparison with stage #2 anymore. We can instead tell the diff-files not to compare with higher stages, and use the unmerged output to update the index to reflect the state of the working tree. The changes to the test vector in t2200 illustrates the nature of the bug and the fix. The test expected stage #1 and #3 entries be left behind, but it was codifying the buggy behaviour. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-04-21 03:11:19 +02:00
switch (fix_unmerged_status(p, data)) {
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
default:
die(_("unexpected diff status %c"), p->status);
diff-lib.c: adjust position of i-t-a entries in diff Entries added by "git add -N" are reminder for the user so that they don't forget to add them before committing. These entries appear in the index even though they are not real. Their presence in the index leads to a confusing "git status" like this: On branch master Changes to be committed: new file: foo Changes not staged for commit: modified: foo If you do a "git commit", "foo" will not be included even though "status" reports it as "to be committed". This patch changes the output to become On branch master Changes not staged for commit: new file: foo no changes added to commit The two hunks in diff-lib.c adjust "diff-index" and "diff-files" so that i-t-a entries appear as new files in diff-files and nothing in diff-index. Due to this change, diff-files may start to report "new files" for the first time. "add -u" needs to be told about this or it will die in denial, screaming "new files can't exist! Reality is wrong." Luckily, it's the only one among run_diff_files() callers that needs fixing. Now in the new world order, a hierarchy in the index that contain i-t-a paths is written out as a tree object as if these i-t-a entries do not exist, and comparing the index with such a tree object that would result from writing out the hierarchy will result in no difference. Update a test in t2203 that expected the i-t-a entries to appear as "added to the index" in the comparison to instead expect no output. An earlier change eec3e7e4 (cache-tree: invalidate i-t-a paths after generating trees, 2012-12-16) becomes an unnecessary pessimization in the new world order---a cache-tree in the index that corresponds to a hierarchy with i-t-a paths can now be marked as valid and record the object name of the tree that results from writing a tree object out of that hierarchy, as it will compare equal to that tree. Reverting the commit is left for the future, though, as it is purely a performance issue and no longer affects correctness. Helped-by: Michael J Gruber <git@drmicha.warpmail.net> Helped-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2015-03-16 14:56:46 +01:00
case DIFF_STATUS_ADDED:
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
if (add_file_to_index(&the_index, path, data->flags)) {
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
die(_("updating files failed"));
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
data->add_errors++;
}
break;
case DIFF_STATUS_DELETED:
if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
break;
if (!(data->flags & ADD_CACHE_PRETEND))
remove_file_from_index(&the_index, path);
if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
printf(_("remove '%s'\n"), path);
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
break;
}
}
}
int add_files_to_cache(const char *prefix,
const struct pathspec *pathspec, int flags)
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
{
struct update_callback_data data;
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
struct rev_info rev;
add -u: only show pathless 'add -u' warning when changes exist outside cwd A common workflow in large projects is to chdir into a subdirectory of interest and only do work there: cd src vi foo.c make test git add -u git commit The upcoming change to 'git add -u' behavior would not affect such a workflow: when the only changes present are in the current directory, 'git add -u' will add all changes, and whether that happens via an implicit "." or implicit ":/" parameter is an unimportant implementation detail. The warning about use of 'git add -u' with no pathspec is annoying because it seemingly serves no purpose in this case. So suppress the warning unless there are changes outside the cwd that are not being added. A previous version of this patch ran two I/O-intensive diff-files passes: one to find changes outside the cwd, and another to find changes to add to the index within the cwd. This version runs one full-tree diff and decides for each change whether to add it or warn and suppress it in update_callback. As a result, even on very large repositories "git add -u" will not be significantly slower than the future default behavior ("git add -u :/"), and the slowdown relative to "git add -u ." should be a useful clue to users of such repositories to get into the habit of explicitly passing '.'. Signed-off-by: Jonathan Nieder <jrnieder@gmail.com> Acked-by: Jeff King <peff@peff.net> Improved-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-03-19 23:50:50 +01:00
memset(&data, 0, sizeof(data));
data.flags = flags;
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
init_revisions(&rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
if (pathspec)
copy_pathspec(&rev.prune_data, pathspec);
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
Fix "add -u" that sometimes fails to resolve unmerged paths "git add -u" updates the index with the updated contents from the working tree by internally running "diff-files" to grab the set of paths that are different from the index. Then it updates the index entries for the paths that are modified in the working tree, and deletes the index entries for the paths that are deleted in the working tree. It ignored the output from the diff-files that indicated that a path is unmerged. For these paths, it instead relied on the fact that an unmerged path is followed by the result of comparison between stage #2 (ours) and the working tree, and used that to update or delete such a path when it is used to record the resolution of a conflict. As the result, when a path did not have stage #2 (e.g. "we deleted while the other side added"), these unmerged stages were left behind, instead of recording what the user resolved in the working tree. Since we recently fixed "diff-files" to indicate if the corresponding path exists on the working tree for an unmerged path, we do not have to rely on the comparison with stage #2 anymore. We can instead tell the diff-files not to compare with higher stages, and use the unmerged output to update the index to reflect the state of the working tree. The changes to the test vector in t2200 illustrates the nature of the bug and the fix. The test expected stage #1 and #3 entries be left behind, but it was codifying the buggy behaviour. Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-04-21 03:11:19 +02:00
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
Remove diff machinery dependency from read-cache Exal Sibeaz pointed out that some git files are way too big, and that add_files_to_cache() brings in all the diff machinery to any git binary that needs the basic git SHA1 object operations from read-cache.c. Which is pretty much all of them. It's doubly silly, since add_files_to_cache() is only used by builtin programs (add, checkout and commit), so it's fairly easily fixed by just moving the thing to builtin-add.c, and avoiding the dependency entirely. I initially argued to Exal that it would probably be best to try to depend on smart compilers and linkers, but after spending some time trying to make -ffunction-sections work and giving up, I think Exal was right, and the fix is to just do some trivial cleanups like this. This trivial cleanup results in pretty stunning file size differences. The diff machinery really is mostly used by just the builtin programs, and you have things like these trivial before-and-after numbers: -rwxr-xr-x 1 torvalds torvalds 1727420 2010-01-21 10:53 git-hash-object -rwxrwxr-x 1 torvalds torvalds 940265 2010-01-21 11:16 git-hash-object Now, I'm not saying that 940kB is good either, but that's mostly all the debug information - you can see the real code with 'size': text data bss dec hex filename 418675 3920 127408 550003 86473 git-hash-object (before) 230650 2288 111728 344666 5425a git-hash-object (after) ie we have a nice 24% size reduction from this trivial cleanup. It's not just that one file either. I get: [torvalds@nehalem git]$ du -s /home/torvalds/libexec/git-core 45640 /home/torvalds/libexec/git-core (before) 33508 /home/torvalds/libexec/git-core (after) so we're talking 12MB of diskspace here. (Of course, stripping all the binaries brings the 33MB down to 9MB, so the whole debug information thing is still the bulk of it all, but that's a separate issue entirely) Now, I'm sure there are other things we should do, and changing our compiler flags from -O2 to -Os would bring the text size down by an additional almost 20%, but this thing Exal pointed out seems to be some good low-hanging fruit. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2010-01-21 20:37:38 +01:00
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
return !!data.add_errors;
}
static char *prune_directory(struct dir_struct *dir, struct pathspec *pathspec, int prefix)
{
char *seen;
int i;
struct dir_entry **src, **dst;
seen = xcalloc(pathspec->nr, 1);
src = dst = dir->entries;
i = dir->nr;
while (--i >= 0) {
struct dir_entry *entry = *src++;
if (dir_path_match(entry, pathspec, prefix, seen))
*dst++ = entry;
}
dir->nr = dst - dir->entries;
add_pathspec_matches_against_index(pathspec, seen);
return seen;
}
static void refresh(int verbose, const struct pathspec *pathspec)
{
char *seen;
int i;
seen = xcalloc(pathspec->nr, 1);
refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
pathspec, seen, _("Unstaged changes after refreshing the index:"));
for (i = 0; i < pathspec->nr; i++) {
if (!seen[i])
die(_("pathspec '%s' did not match any files"),
pathspec->items[i].match);
}
free(seen);
}
int run_add_interactive(const char *revision, const char *patch_mode,
const struct pathspec *pathspec)
{
int status, i;
struct argv_array argv = ARGV_ARRAY_INIT;
argv_array_push(&argv, "add--interactive");
if (patch_mode)
argv_array_push(&argv, patch_mode);
if (revision)
argv_array_push(&argv, revision);
argv_array_push(&argv, "--");
for (i = 0; i < pathspec->nr; i++)
/* pass original pathspec, to be re-parsed */
argv_array_push(&argv, pathspec->items[i].original);
status = run_command_v_opt(argv.argv, RUN_GIT_CMD);
argv_array_clear(&argv);
return status;
}
int interactive_add(int argc, const char **argv, const char *prefix, int patch)
{
struct pathspec pathspec;
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH |
PATHSPEC_PREFIX_ORIGIN,
prefix, argv);
return run_add_interactive(NULL,
patch ? "--patch" : NULL,
&pathspec);
}
static int edit_patch(int argc, const char **argv, const char *prefix)
{
char *file = git_pathdup("ADD_EDIT.patch");
const char *apply_argv[] = { "apply", "--recount", "--cached",
NULL, NULL };
struct child_process child = CHILD_PROCESS_INIT;
struct rev_info rev;
int out;
struct stat st;
apply_argv[3] = file;
git_config(git_diff_basic_config, NULL); /* no "diff" UI options */
if (read_cache() < 0)
die(_("Could not read the index"));
init_revisions(&rev, prefix);
rev.diffopt.context = 7;
argc = setup_revisions(argc, argv, &rev, NULL);
rev.diffopt.output_format = DIFF_FORMAT_PATCH;
rev.diffopt.use_color = 0;
DIFF_OPT_SET(&rev.diffopt, IGNORE_DIRTY_SUBMODULES);
out = open(file, O_CREAT | O_WRONLY, 0666);
if (out < 0)
die(_("Could not open '%s' for writing."), file);
rev.diffopt.file = xfdopen(out, "w");
rev.diffopt.close_file = 1;
if (run_diff_files(&rev, 0))
die(_("Could not write patch"));
launch_editor(file, NULL, NULL);
if (stat(file, &st))
die_errno(_("Could not stat '%s'"), file);
if (!st.st_size)
die(_("Empty patch. Aborted."));
child.git_cmd = 1;
child.argv = apply_argv;
if (run_command(&child))
die(_("Could not apply '%s'"), file);
unlink(file);
free(file);
return 0;
}
static struct lock_file lock_file;
static const char ignore_error[] =
N_("The following paths are ignored by one of your .gitignore files:\n");
static int verbose, show_only, ignored_too, refresh_only;
static int ignore_add_errors, intent_to_add, ignore_missing;
#define ADDREMOVE_DEFAULT 1
static int addremove = ADDREMOVE_DEFAULT;
static int addremove_explicit = -1; /* unspecified */
static int ignore_removal_cb(const struct option *opt, const char *arg, int unset)
{
/* if we are told to ignore, we are not adding removals */
*(int *)opt->value = !unset ? 0 : 1;
return 0;
}
static struct option builtin_add_options[] = {
OPT__DRY_RUN(&show_only, N_("dry run")),
OPT__VERBOSE(&verbose, N_("be verbose")),
OPT_GROUP(""),
OPT_BOOL('i', "interactive", &add_interactive, N_("interactive picking")),
OPT_BOOL('p', "patch", &patch_interactive, N_("select hunks interactively")),
OPT_BOOL('e', "edit", &edit_interactive, N_("edit current diff and apply")),
OPT__FORCE(&ignored_too, N_("allow adding otherwise ignored files")),
OPT_BOOL('u', "update", &take_worktree_changes, N_("update tracked files")),
OPT_BOOL('N', "intent-to-add", &intent_to_add, N_("record only the fact that the path will be added later")),
OPT_BOOL('A', "all", &addremove_explicit, N_("add changes from all tracked and untracked files")),
{ OPTION_CALLBACK, 0, "ignore-removal", &addremove_explicit,
NULL /* takes no arguments */,
N_("ignore paths removed in the working tree (same as --no-all)"),
PARSE_OPT_NOARG, ignore_removal_cb },
OPT_BOOL( 0 , "refresh", &refresh_only, N_("don't add, only refresh the index")),
OPT_BOOL( 0 , "ignore-errors", &ignore_add_errors, N_("just skip files which cannot be added because of errors")),
OPT_BOOL( 0 , "ignore-missing", &ignore_missing, N_("check if - even missing - files are ignored in dry run")),
OPT_END(),
};
static int add_config(const char *var, const char *value, void *cb)
{
if (!strcmp(var, "add.ignoreerrors") ||
!strcmp(var, "add.ignore-errors")) {
ignore_add_errors = git_config_bool(var, value);
return 0;
}
return git_default_config(var, value, cb);
}
static int add_files(struct dir_struct *dir, int flags)
{
int i, exit_status = 0;
if (dir->ignored_nr) {
fprintf(stderr, _(ignore_error));
for (i = 0; i < dir->ignored_nr; i++)
fprintf(stderr, "%s\n", dir->ignored[i]->name);
fprintf(stderr, _("Use -f if you really want to add them.\n"));
exit_status = 1;
}
for (i = 0; i < dir->nr; i++)
if (add_file_to_cache(dir->entries[i]->name, flags)) {
if (!ignore_add_errors)
die(_("adding files failed"));
exit_status = 1;
}
return exit_status;
}
int cmd_add(int argc, const char **argv, const char *prefix)
{
int exit_status = 0;
struct pathspec pathspec;
struct dir_struct dir;
int flags;
int add_new_files;
int require_pathspec;
char *seen = NULL;
git-add --interactive A script to be driven when the user says "git add --interactive" is introduced. When it is run, first it runs its internal 'status' command to show the current status, and then goes into its internactive command loop. The command loop shows the list of subcommands available, and gives a prompt "What now> ". In general, when the prompt ends with a single '>', you can pick only one of the choices given and type return, like this: *** Commands *** 1: status 2: update 3: revert 4: add untracked 5: patch 6: diff 7: quit 8: help What now> 1 You also could say "s" or "sta" or "status" above as long as the choice is unique. The main command loop has 6 subcommands (plus help and quit). * 'status' shows the change between HEAD and index (i.e. what will be committed if you say "git commit"), and between index and working tree files (i.e. what you could stage further before "git commit" using "git-add") for each path. A sample output looks like this: staged unstaged path 1: binary nothing foo.png 2: +403/-35 +1/-1 git-add--interactive.perl It shows that foo.png has differences from HEAD (but that is binary so line count cannot be shown) and there is no difference between indexed copy and the working tree version (if the working tree version were also different, 'binary' would have been shown in place of 'nothing'). The other file, git-add--interactive.perl, has 403 lines added and 35 lines deleted if you commit what is in the index, but working tree file has further modifications (one addition and one deletion). * 'update' shows the status information and gives prompt "Update>>". When the prompt ends with double '>>', you can make more than one selection, concatenated with whitespace or comma. Also you can say ranges. E.g. "2-5 7,9" to choose 2,3,4,5,7,9 from the list. You can say '*' to choose everything. What you chose are then highlighted with '*', like this: staged unstaged path 1: binary nothing foo.png * 2: +403/-35 +1/-1 git-add--interactive.perl To remove selection, prefix the input with - like this: Update>> -2 After making the selection, answer with an empty line to stage the contents of working tree files for selected paths in the index. * 'revert' has a very similar UI to 'update', and the staged information for selected paths are reverted to that of the HEAD version. Reverting new paths makes them untracked. * 'add untracked' has a very similar UI to 'update' and 'revert', and lets you add untracked paths to the index. * 'patch' lets you choose one path out of 'status' like selection. After choosing the path, it presents diff between the index and the working tree file and asks you if you want to stage the change of each hunk. You can say: y - add the change from that hunk to index n - do not add the change from that hunk to index a - add the change from that hunk and all the rest to index d - do not the change from that hunk nor any of the rest to index j - do not decide on this hunk now, and view the next undecided hunk J - do not decide on this hunk now, and view the next hunk k - do not decide on this hunk now, and view the previous undecided hunk K - do not decide on this hunk now, and view the previous hunk After deciding the fate for all hunks, if there is any hunk that was chosen, the index is updated with the selected hunks. * 'diff' lets you review what will be committed (i.e. between HEAD and index). This is still rough, but does everything except a few things I think are needed. * 'patch' should be able to allow splitting a hunk into multiple hunks. * 'patch' does not adjust the line offsets @@ -k,l +m,n @@ in the hunk header. This does not have major problem in practice, but it _should_ do the adjustment. * It does not have any explicit support for a merge in progress; it may not work at all. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-12-11 05:55:50 +01:00
git_config(add_config, NULL);
argc = parse_options(argc, argv, prefix, builtin_add_options,
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
if (patch_interactive)
add_interactive = 1;
if (add_interactive)
exit(interactive_add(argc - 1, argv + 1, prefix, patch_interactive));
if (edit_interactive)
return(edit_patch(argc, argv, prefix));
argc--;
argv++;
if (0 <= addremove_explicit)
addremove = addremove_explicit;
else if (take_worktree_changes && ADDREMOVE_DEFAULT)
addremove = 0; /* "-u" was given but not "-A" */
if (addremove && take_worktree_changes)
die(_("-A and -u are mutually incompatible"));
if (!take_worktree_changes && addremove_explicit < 0 && argc)
/* Turn "git add pathspec..." to "git add -A pathspec..." */
addremove = 1;
if (!show_only && ignore_missing)
die(_("Option --ignore-missing can only be used together with --dry-run"));
if ((0 < addremove_explicit || take_worktree_changes) && !argc) {
static const char *whole[2] = { ":/", NULL };
argc = 1;
argv = whole;
}
add_new_files = !take_worktree_changes && !refresh_only;
require_pathspec = !take_worktree_changes;
hold_locked_index(&lock_file, 1);
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));
if (require_pathspec && argc == 0) {
fprintf(stderr, _("Nothing specified, nothing added.\n"));
fprintf(stderr, _("Maybe you wanted to say 'git add .'?\n"));
return 0;
}
if (read_cache() < 0)
die(_("index file corrupt"));
/*
* Check the "pathspec '%s' did not match any files" block
* below before enabling new magic.
*/
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_FULL |
PATHSPEC_SYMLINK_LEADING_PATH |
PATHSPEC_STRIP_SUBMODULE_SLASH_EXPENSIVE,
prefix, argv);
if (add_new_files) {
int baselen;
struct pathspec empty_pathspec;
/* Set up the default git porcelain excludes */
memset(&dir, 0, sizeof(dir));
if (!ignored_too) {
dir.flags |= DIR_COLLECT_IGNORED;
setup_standard_excludes(&dir);
}
memset(&empty_pathspec, 0, sizeof(empty_pathspec));
/* This picks up the paths that are not tracked */
baselen = fill_directory(&dir, &pathspec);
if (pathspec.nr)
seen = prune_directory(&dir, &pathspec, baselen);
}
if (refresh_only) {
refresh(verbose, &pathspec);
goto finish;
}
if (pathspec.nr) {
int i;
if (!seen)
seen = find_pathspecs_matching_against_index(&pathspec);
/*
* file_exists() assumes exact match
*/
GUARD_PATHSPEC(&pathspec,
PATHSPEC_FROMTOP |
PATHSPEC_LITERAL |
PATHSPEC_GLOB |
PATHSPEC_ICASE |
PATHSPEC_EXCLUDE);
for (i = 0; i < pathspec.nr; i++) {
const char *path = pathspec.items[i].match;
if (pathspec.items[i].magic & PATHSPEC_EXCLUDE)
continue;
if (!seen[i] && path[0] &&
((pathspec.items[i].magic &
(PATHSPEC_GLOB | PATHSPEC_ICASE)) ||
!file_exists(path))) {
if (ignore_missing) {
int dtype = DT_UNKNOWN;
if (is_excluded(&dir, path, &dtype))
dir_add_ignored(&dir, path, pathspec.items[i].len);
} else
die(_("pathspec '%s' did not match any files"),
pathspec.items[i].original);
}
}
free(seen);
}
plug_bulk_checkin();
exit_status |= add_files_to_cache(prefix, &pathspec, flags);
if (add_new_files)
exit_status |= add_files(&dir, flags);
unplug_bulk_checkin();
finish:
if (active_cache_changed) {
if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
die(_("Unable to write new index file"));
}
return exit_status;
}