2006-05-17 18:33:32 +02:00
|
|
|
/*
|
|
|
|
* "git add" builtin command
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Linus Torvalds
|
|
|
|
*/
|
|
|
|
#include "cache.h"
|
|
|
|
#include "builtin.h"
|
|
|
|
#include "dir.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"
|
2006-05-20 10:28:49 +02:00
|
|
|
#include "cache-tree.h"
|
2007-09-18 02:06:44 +02:00
|
|
|
#include "run-command.h"
|
2007-10-03 23:45:02 +02:00
|
|
|
#include "parse-options.h"
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
#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"
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
#include "revision.h"
|
2006-05-17 18:33:32 +02:00
|
|
|
|
2007-10-03 23:45:02 +02:00
|
|
|
static const char * const builtin_add_usage[] = {
|
2008-07-13 15:36:15 +02:00
|
|
|
"git add [options] [--] <filepattern>...",
|
2007-10-03 23:45:02 +02:00
|
|
|
NULL
|
|
|
|
};
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
static int patch_interactive, add_interactive, edit_interactive;
|
2007-05-12 08:42:00 +02:00
|
|
|
static int take_worktree_changes;
|
2007-02-28 04:31:10 +01:00
|
|
|
|
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
|
|
|
|
{
|
|
|
|
int flags;
|
|
|
|
int add_errors;
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
switch (p->status) {
|
|
|
|
default:
|
|
|
|
die("unexpected diff status %c", p->status);
|
|
|
|
case DIFF_STATUS_UNMERGED:
|
|
|
|
/*
|
|
|
|
* ADD_CACHE_IGNORE_REMOVAL is unset if "git
|
|
|
|
* add -u" is calling us, In such a case, a
|
|
|
|
* missing work tree file needs to be removed
|
|
|
|
* if there is an unmerged entry at stage #2,
|
|
|
|
* but such a diff record is followed by
|
|
|
|
* another with DIFF_STATUS_DELETED (and if
|
|
|
|
* there is no stage #2, we won't see DELETED
|
|
|
|
* nor MODIFIED). We can simply continue
|
|
|
|
* either way.
|
|
|
|
*/
|
|
|
|
if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL))
|
|
|
|
continue;
|
|
|
|
/*
|
|
|
|
* Otherwise, it is "git add path" is asking
|
|
|
|
* to explicitly add it; we fall through. A
|
|
|
|
* missing work tree file is an error and is
|
|
|
|
* caught by add_file_to_index() in such a
|
|
|
|
* case.
|
|
|
|
*/
|
|
|
|
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");
|
|
|
|
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);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
|
|
|
|
{
|
|
|
|
struct update_callback_data data;
|
|
|
|
struct rev_info rev;
|
|
|
|
init_revisions(&rev, prefix);
|
|
|
|
setup_revisions(0, NULL, &rev, NULL);
|
|
|
|
rev.prune_data = pathspec;
|
|
|
|
rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
|
|
|
|
rev.diffopt.format_callback = update_callback;
|
|
|
|
data.flags = flags;
|
|
|
|
data.add_errors = 0;
|
|
|
|
rev.diffopt.format_callback_data = &data;
|
|
|
|
run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
|
|
|
|
return !!data.add_errors;
|
|
|
|
}
|
|
|
|
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
|
|
|
|
{
|
|
|
|
int num_unmatched = 0, i;
|
|
|
|
|
|
|
|
/*
|
2008-12-10 23:27:44 +01:00
|
|
|
* Since we are walking the index as if we were walking the directory,
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
* we have to mark the matched pathspec as seen; otherwise we will
|
|
|
|
* mistakenly think that the user gave a pathspec that did not match
|
|
|
|
* anything.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < specs; i++)
|
|
|
|
if (!seen[i])
|
|
|
|
num_unmatched++;
|
|
|
|
if (!num_unmatched)
|
|
|
|
return;
|
|
|
|
for (i = 0; i < active_nr; i++) {
|
|
|
|
struct cache_entry *ce = active_cache[i];
|
|
|
|
match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, seen);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-05-17 18:33:32 +02:00
|
|
|
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
|
|
|
{
|
2006-05-17 22:23:19 +02:00
|
|
|
char *seen;
|
|
|
|
int i, specs;
|
2006-05-17 18:33:32 +02:00
|
|
|
struct dir_entry **src, **dst;
|
|
|
|
|
2006-05-17 22:23:19 +02:00
|
|
|
for (specs = 0; pathspec[specs]; specs++)
|
|
|
|
/* nothing */;
|
2006-07-25 09:30:18 +02:00
|
|
|
seen = xcalloc(specs, 1);
|
2006-05-17 22:23:19 +02:00
|
|
|
|
2006-05-17 18:33:32 +02:00
|
|
|
src = dst = dir->entries;
|
|
|
|
i = dir->nr;
|
|
|
|
while (--i >= 0) {
|
|
|
|
struct dir_entry *entry = *src++;
|
2006-12-29 20:01:31 +01:00
|
|
|
if (match_pathspec(pathspec, entry->name, entry->len,
|
|
|
|
prefix, seen))
|
|
|
|
*dst++ = entry;
|
2006-05-17 18:33:32 +02:00
|
|
|
}
|
|
|
|
dir->nr = dst - dir->entries;
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
fill_pathspec_matches(pathspec, seen, specs);
|
2006-05-17 22:23:19 +02:00
|
|
|
|
|
|
|
for (i = 0; i < specs; i++) {
|
2009-04-29 05:21:01 +02:00
|
|
|
if (!seen[i] && pathspec[i][0] && !file_exists(pathspec[i]))
|
builtin-add: simplify (and increase accuracy of) exclude handling
Previously, the code would always set up the excludes, and then manually
pick through the pathspec we were given, assuming that non-added but
existing paths were just ignored. This was mostly correct, but would
erroneously mark a totally empty directory as 'ignored'.
Instead, we now use the collect_ignored option of dir_struct, which
unambiguously tells us whether a path was ignored. This simplifies the
code, and means empty directories are now just not mentioned at all.
Furthermore, we now conditionally ask dir_struct to respect excludes,
depending on whether the '-f' flag has been set. This means we don't have
to pick through the result, checking for an 'ignored' flag; ignored entries
were either added or not in the first place.
We can safely get rid of the special 'ignored' flags to dir_entry, which
were not used anywhere else.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Jonas Fonseca <fonseca@diku.dk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-06-12 23:42:14 +02:00
|
|
|
die("pathspec '%s' did not match any files",
|
|
|
|
pathspec[i]);
|
2006-05-17 22:23:19 +02:00
|
|
|
}
|
2007-10-29 08:00:33 +01:00
|
|
|
free(seen);
|
2006-05-17 18:33:32 +02:00
|
|
|
}
|
|
|
|
|
2009-01-02 19:08:40 +01:00
|
|
|
static void treat_gitlinks(const char **pathspec)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!pathspec || !*pathspec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < active_nr; i++) {
|
|
|
|
struct cache_entry *ce = active_cache[i];
|
|
|
|
if (S_ISGITLINK(ce->ce_mode)) {
|
|
|
|
int len = ce_namelen(ce), j;
|
|
|
|
for (j = 0; pathspec[j]; j++) {
|
|
|
|
int len2 = strlen(pathspec[j]);
|
|
|
|
if (len2 <= len || pathspec[j][len] != '/' ||
|
|
|
|
memcmp(ce->name, pathspec[j], len))
|
|
|
|
continue;
|
|
|
|
if (len2 == len + 1)
|
|
|
|
/* strip trailing slash */
|
|
|
|
pathspec[j] = xstrndup(ce->name, len);
|
|
|
|
else
|
|
|
|
die ("Path '%s' is in submodule '%.*s'",
|
|
|
|
pathspec[j], len, ce->name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-08-11 23:59:01 +02:00
|
|
|
static void refresh(int verbose, const char **pathspec)
|
|
|
|
{
|
|
|
|
char *seen;
|
|
|
|
int i, specs;
|
|
|
|
|
|
|
|
for (specs = 0; pathspec[specs]; specs++)
|
|
|
|
/* nothing */;
|
|
|
|
seen = xcalloc(specs, 1);
|
2009-08-21 10:57:58 +02:00
|
|
|
refresh_index(&the_index, verbose ? REFRESH_IN_PORCELAIN : REFRESH_QUIET,
|
2009-08-21 10:57:59 +02:00
|
|
|
pathspec, seen, "Unstaged changes after refreshing the index:");
|
2007-08-11 23:59:01 +02:00
|
|
|
for (i = 0; i < specs; i++) {
|
|
|
|
if (!seen[i])
|
|
|
|
die("pathspec '%s' did not match any files", pathspec[i]);
|
|
|
|
}
|
2007-10-29 08:00:33 +01:00
|
|
|
free(seen);
|
2007-08-11 23:59:01 +02:00
|
|
|
}
|
|
|
|
|
2007-11-25 19:10:10 +01:00
|
|
|
static const char **validate_pathspec(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
|
|
|
const char **pathspec = get_pathspec(prefix, argv);
|
|
|
|
|
2008-08-04 09:52:37 +02:00
|
|
|
if (pathspec) {
|
|
|
|
const char **p;
|
|
|
|
for (p = pathspec; *p; p++) {
|
2009-02-09 21:54:06 +01:00
|
|
|
if (has_symlink_leading_path(*p, strlen(*p))) {
|
2008-08-04 09:52:37 +02:00
|
|
|
int len = prefix ? strlen(prefix) : 0;
|
|
|
|
die("'%s' is beyond a symbolic link", *p + len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-25 19:10:10 +01:00
|
|
|
return pathspec;
|
|
|
|
}
|
|
|
|
|
2009-08-13 14:29:41 +02:00
|
|
|
int run_add_interactive(const char *revision, const char *patch_mode,
|
|
|
|
const char **pathspec)
|
2007-09-18 02:06:44 +02:00
|
|
|
{
|
2009-08-13 14:29:41 +02:00
|
|
|
int status, ac, pc = 0;
|
2007-11-25 19:10:10 +01:00
|
|
|
const char **args;
|
|
|
|
|
2009-08-13 14:29:41 +02:00
|
|
|
if (pathspec)
|
|
|
|
while (pathspec[pc])
|
|
|
|
pc++;
|
2007-11-25 19:07:55 +01:00
|
|
|
|
2009-08-13 14:29:41 +02:00
|
|
|
args = xcalloc(sizeof(const char *), (pc + 5));
|
2007-11-25 14:15:42 +01:00
|
|
|
ac = 0;
|
|
|
|
args[ac++] = "add--interactive";
|
2009-08-13 14:29:41 +02:00
|
|
|
if (patch_mode)
|
|
|
|
args[ac++] = patch_mode;
|
|
|
|
if (revision)
|
|
|
|
args[ac++] = revision;
|
2007-11-25 14:15:42 +01:00
|
|
|
args[ac++] = "--";
|
2009-08-13 14:29:41 +02:00
|
|
|
if (pc) {
|
|
|
|
memcpy(&(args[ac]), pathspec, sizeof(const char *) * pc);
|
|
|
|
ac += pc;
|
2007-11-25 14:15:42 +01:00
|
|
|
}
|
|
|
|
args[ac] = NULL;
|
2007-11-22 01:02:52 +01:00
|
|
|
|
|
|
|
status = run_command_v_opt(args, RUN_GIT_CMD);
|
|
|
|
free(args);
|
|
|
|
return status;
|
2007-09-18 02:06:44 +02:00
|
|
|
}
|
|
|
|
|
2009-08-13 14:29:41 +02:00
|
|
|
int interactive_add(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
|
|
|
const char **pathspec = NULL;
|
|
|
|
|
|
|
|
if (argc) {
|
|
|
|
pathspec = validate_pathspec(argc, argv, prefix);
|
|
|
|
if (!pathspec)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return run_add_interactive(NULL,
|
|
|
|
patch_interactive ? "--patch" : NULL,
|
|
|
|
pathspec);
|
|
|
|
}
|
|
|
|
|
2009-06-18 19:28:43 +02:00
|
|
|
static int edit_patch(int argc, const char **argv, const char *prefix)
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
{
|
|
|
|
char *file = xstrdup(git_path("ADD_EDIT.patch"));
|
|
|
|
const char *apply_argv[] = { "apply", "--recount", "--cached",
|
|
|
|
file, NULL };
|
|
|
|
struct child_process child;
|
|
|
|
struct rev_info rev;
|
|
|
|
int out;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
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;
|
|
|
|
out = open(file, O_CREAT | O_WRONLY, 0644);
|
|
|
|
if (out < 0)
|
|
|
|
die ("Could not open '%s' for writing.", file);
|
2009-09-12 10:43:27 +02:00
|
|
|
rev.diffopt.file = xfdopen(out, "w");
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
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))
|
2009-06-27 17:58:47 +02:00
|
|
|
die_errno("Could not stat '%s'", file);
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
if (!st.st_size)
|
|
|
|
die("Empty patch. Aborted.");
|
|
|
|
|
|
|
|
memset(&child, 0, sizeof(child));
|
|
|
|
child.git_cmd = 1;
|
|
|
|
child.argv = apply_argv;
|
|
|
|
if (run_command(&child))
|
|
|
|
die ("Could not apply '%s'", file);
|
|
|
|
|
|
|
|
unlink(file);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-06-06 21:51:49 +02:00
|
|
|
static struct lock_file lock_file;
|
2006-05-17 18:33:32 +02:00
|
|
|
|
2007-08-29 00:41:23 +02:00
|
|
|
static const char ignore_error[] =
|
2006-12-26 02:46:38 +01:00
|
|
|
"The following paths are ignored by one of your .gitignore files:\n";
|
|
|
|
|
2007-10-03 23:45:02 +02:00
|
|
|
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
2008-08-21 10:44:53 +02:00
|
|
|
static int ignore_add_errors, addremove, intent_to_add;
|
2007-10-03 23:45:02 +02:00
|
|
|
|
|
|
|
static struct option builtin_add_options[] = {
|
|
|
|
OPT__DRY_RUN(&show_only),
|
|
|
|
OPT__VERBOSE(&verbose),
|
|
|
|
OPT_GROUP(""),
|
|
|
|
OPT_BOOLEAN('i', "interactive", &add_interactive, "interactive picking"),
|
2007-11-25 14:15:42 +01:00
|
|
|
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
OPT_BOOLEAN('e', "edit", &edit_interactive, "edit current diff and apply"),
|
2008-06-14 11:48:00 +02:00
|
|
|
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
|
|
|
|
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
|
2008-08-21 10:44:53 +02:00
|
|
|
OPT_BOOLEAN('N', "intent-to-add", &intent_to_add, "record only the fact that the path will be added later"),
|
git-add --all: add all files
People sometimes find that "git add -u && git add ." are 13 keystrokes too
many. This reduces it by nine.
The support of this has been very low priority for me personally, because
I almost never do "git add ." in a directory with already tracked files,
and in a new directory, there is no point saying "git add -u".
However, for two types of people (that are very different from me), this
mode of operation may make sense and there is no reason to leave it
unsupported. That is:
(1) If you are extremely well disciplined and keep perfect .gitignore, it
always is safe to say "git add ."; or
(2) If you are extremely undisciplined and do not even know what files
you created, and you do not very much care what goes in your history,
it does not matter if "git add ." included everything.
So there it is, although I suspect I will not use it myself, ever.
It will be too much of a change that is against the expectation of the
existing users to allow "git commit -a" to include untracked files, and
it would be inconsistent if we named this new option "-a", so the short
option is "-A". We _might_ want to later add "git commit -A" but that is
a separate topic.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-20 04:51:11 +02:00
|
|
|
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
|
2007-10-03 23:45:02 +02:00
|
|
|
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
2008-05-12 19:58:29 +02:00
|
|
|
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
|
2007-10-03 23:45:02 +02:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2008-05-25 23:25:02 +02:00
|
|
|
static int add_config(const char *var, const char *value, void *cb)
|
2008-05-12 19:59:23 +02:00
|
|
|
{
|
|
|
|
if (!strcasecmp(var, "add.ignore-errors")) {
|
|
|
|
ignore_add_errors = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-05-25 23:25:02 +02:00
|
|
|
return git_default_config(var, value, cb);
|
2008-05-12 19:59:23 +02:00
|
|
|
}
|
|
|
|
|
2008-07-20 04:22:25 +02:00
|
|
|
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");
|
|
|
|
die("no files added");
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2006-07-29 07:44:25 +02:00
|
|
|
int cmd_add(int argc, const char **argv, const char *prefix)
|
2006-05-17 18:33:32 +02:00
|
|
|
{
|
2008-05-12 19:58:10 +02:00
|
|
|
int exit_status = 0;
|
2008-07-20 04:22:25 +02:00
|
|
|
int newfd;
|
2006-05-17 18:33:32 +02:00
|
|
|
const char **pathspec;
|
|
|
|
struct dir_struct dir;
|
2008-05-22 23:59:42 +02:00
|
|
|
int flags;
|
2008-07-20 04:22:25 +02:00
|
|
|
int add_new_files;
|
|
|
|
int require_pathspec;
|
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
|
|
|
|
2009-06-18 11:17:54 +02:00
|
|
|
git_config(add_config, NULL);
|
|
|
|
|
2009-05-23 20:53:12 +02:00
|
|
|
argc = parse_options(argc, argv, prefix, builtin_add_options,
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
builtin_add_usage, PARSE_OPT_KEEP_ARGV0);
|
2007-11-25 14:15:42 +01:00
|
|
|
if (patch_interactive)
|
|
|
|
add_interactive = 1;
|
2007-11-22 01:02:52 +01:00
|
|
|
if (add_interactive)
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
exit(interactive_add(argc - 1, argv + 1, prefix));
|
2006-05-17 18:33:32 +02:00
|
|
|
|
git-add: introduce --edit (to edit the diff vs. the index)
With "git add -e [<files>]", Git will fire up an editor with the current
diff relative to the index (i.e. what you would get with "git diff
[<files>]").
Now you can edit the patch as much as you like, including adding/removing
lines, editing the text, whatever. Make sure, though, that the first
character of the hunk lines is still a space, a plus or a minus.
After you closed the editor, Git will adjust the line counts of the hunks
if necessary, thanks to the --recount option of apply, and commit the
patch. Except if you deleted everything, in which case nothing happens
(for obvious reasons).
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2009-04-08 23:30:24 +02:00
|
|
|
if (edit_interactive)
|
|
|
|
return(edit_patch(argc, argv, prefix));
|
|
|
|
argc--;
|
|
|
|
argv++;
|
|
|
|
|
git-add --all: add all files
People sometimes find that "git add -u && git add ." are 13 keystrokes too
many. This reduces it by nine.
The support of this has been very low priority for me personally, because
I almost never do "git add ." in a directory with already tracked files,
and in a new directory, there is no point saying "git add -u".
However, for two types of people (that are very different from me), this
mode of operation may make sense and there is no reason to leave it
unsupported. That is:
(1) If you are extremely well disciplined and keep perfect .gitignore, it
always is safe to say "git add ."; or
(2) If you are extremely undisciplined and do not even know what files
you created, and you do not very much care what goes in your history,
it does not matter if "git add ." included everything.
So there it is, although I suspect I will not use it myself, ever.
It will be too much of a change that is against the expectation of the
existing users to allow "git commit -a" to include untracked files, and
it would be inconsistent if we named this new option "-a", so the short
option is "-A". We _might_ want to later add "git commit -A" but that is
a separate topic.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-20 04:51:11 +02:00
|
|
|
if (addremove && take_worktree_changes)
|
|
|
|
die("-A and -u are mutually incompatible");
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
if ((addremove || take_worktree_changes) && !argc) {
|
git-add --all: add all files
People sometimes find that "git add -u && git add ." are 13 keystrokes too
many. This reduces it by nine.
The support of this has been very low priority for me personally, because
I almost never do "git add ." in a directory with already tracked files,
and in a new directory, there is no point saying "git add -u".
However, for two types of people (that are very different from me), this
mode of operation may make sense and there is no reason to leave it
unsupported. That is:
(1) If you are extremely well disciplined and keep perfect .gitignore, it
always is safe to say "git add ."; or
(2) If you are extremely undisciplined and do not even know what files
you created, and you do not very much care what goes in your history,
it does not matter if "git add ." included everything.
So there it is, although I suspect I will not use it myself, ever.
It will be too much of a change that is against the expectation of the
existing users to allow "git commit -a" to include untracked files, and
it would be inconsistent if we named this new option "-a", so the short
option is "-A". We _might_ want to later add "git commit -A" but that is
a separate topic.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-20 04:51:11 +02:00
|
|
|
static const char *here[2] = { ".", NULL };
|
|
|
|
argc = 1;
|
|
|
|
argv = here;
|
|
|
|
}
|
|
|
|
|
2008-07-20 04:22:25 +02:00
|
|
|
add_new_files = !take_worktree_changes && !refresh_only;
|
|
|
|
require_pathspec = !take_worktree_changes;
|
|
|
|
|
_GIT_INDEX_OUTPUT: allow plumbing to output to an alternative index file.
When defined, this allows plumbing commands that update the
index (add, apply, checkout-index, merge-recursive, mv,
read-tree, rm, update-index, and write-tree) to write their
resulting index to an alternative index file while holding a
lock to the original index file. With this, git-commit that
jumps the index does not have to make an extra copy of the index
file, and more importantly, it can do the update while holding
the lock on the index.
However, I think the interface to let an environment variable
specify the output is a mistake, as shown in the documentation.
If a curious user has the environment variable set to something
other than the file GIT_INDEX_FILE points at, almost everything
will break. This should instead be a command line parameter to
tell these plumbing commands to write the result in the named
file, to prevent stupid mistakes.
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-04-01 08:09:02 +02:00
|
|
|
newfd = hold_locked_index(&lock_file, 1);
|
2006-05-17 18:33:32 +02:00
|
|
|
|
2008-05-22 23:59:42 +02:00
|
|
|
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
|
2008-05-25 23:03:50 +02:00
|
|
|
(show_only ? ADD_CACHE_PRETEND : 0) |
|
2008-08-21 10:44:53 +02:00
|
|
|
(intent_to_add ? ADD_CACHE_INTENT : 0) |
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
|
|
|
(!(addremove || take_worktree_changes)
|
|
|
|
? ADD_CACHE_IGNORE_REMOVAL : 0));
|
2008-05-22 23:59:42 +02:00
|
|
|
|
2008-07-20 04:22:25 +02:00
|
|
|
if (require_pathspec && argc == 0) {
|
2006-12-20 22:06:46 +01:00
|
|
|
fprintf(stderr, "Nothing specified, nothing added.\n");
|
|
|
|
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-04 09:52:37 +02:00
|
|
|
pathspec = validate_pathspec(argc, argv, prefix);
|
2006-05-17 18:33:32 +02:00
|
|
|
|
2006-12-04 17:13:39 +01:00
|
|
|
if (read_cache() < 0)
|
|
|
|
die("index file corrupt");
|
2009-01-02 19:08:40 +01:00
|
|
|
treat_gitlinks(pathspec);
|
2006-12-04 17:13:39 +01:00
|
|
|
|
2009-05-14 22:22:36 +02:00
|
|
|
if (add_new_files) {
|
|
|
|
int baselen;
|
|
|
|
|
|
|
|
/* Set up the default git porcelain excludes */
|
|
|
|
memset(&dir, 0, sizeof(dir));
|
|
|
|
if (!ignored_too) {
|
|
|
|
dir.flags |= DIR_COLLECT_IGNORED;
|
|
|
|
setup_standard_excludes(&dir);
|
|
|
|
}
|
|
|
|
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
/* This picks up the paths that are not tracked */
|
2009-05-14 22:22:36 +02:00
|
|
|
baselen = fill_directory(&dir, pathspec);
|
|
|
|
if (pathspec)
|
|
|
|
prune_directory(&dir, pathspec, baselen);
|
|
|
|
}
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
|
2008-07-20 04:22:25 +02:00
|
|
|
if (refresh_only) {
|
|
|
|
refresh(verbose, pathspec);
|
|
|
|
goto finish;
|
2006-12-26 02:46:38 +01:00
|
|
|
}
|
|
|
|
|
builtin-add.c: optimize -A option and "git add ."
The earlier "git add -A" change was done in a quite inefficient
way (i.e. it is as unefficient as "git add -u && git add ." modulo
one fork/exec and read/write index).
When the user asks "git add .", we do not have to examine all paths
we encounter and perform the excluded() and dir_add_name()
processing, both of which are slower code and use slower data structure
by git standards, especially when the index is already populated.
Instead, we implement "git add $pathspec..." as:
- read the index;
- read_directory() to process untracked, unignored files the current
way, that is, recursively doing readdir(), filtering them by pathspec
and excluded(), queueing them via dir_add_name() and finally do
add_files(); and
- iterate over the index, filtering them by pathspec, and update only
the modified/type changed paths but not deleted ones.
And "git add -A" becomes exactly the same as above, modulo:
- missing $pathspec means "." instead of being an error; and
- "iterate over the index" part handles deleted ones as well,
i.e. exactly what the current update_callback() in builtin-add.c does.
In either case, because fill_directory() does not use read_directory() to
read everything in, we need to add an extra logic to iterate over the
index to catch mistyped pathspec.
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-07-23 07:30:40 +02:00
|
|
|
exit_status |= add_files_to_cache(prefix, pathspec, flags);
|
2008-07-20 04:22:25 +02:00
|
|
|
|
|
|
|
if (add_new_files)
|
|
|
|
exit_status |= add_files(&dir, flags);
|
2006-05-17 18:33:32 +02:00
|
|
|
|
2007-04-20 10:39:39 +02:00
|
|
|
finish:
|
2006-05-17 18:33:32 +02:00
|
|
|
if (active_cache_changed) {
|
|
|
|
if (write_cache(newfd, active_cache, active_nr) ||
|
2008-01-16 20:12:46 +01:00
|
|
|
commit_locked_index(&lock_file))
|
2006-05-17 18:33:32 +02:00
|
|
|
die("Unable to write new index file");
|
|
|
|
}
|
|
|
|
|
2008-05-12 19:58:10 +02:00
|
|
|
return exit_status;
|
2006-05-17 18:33:32 +02:00
|
|
|
}
|