2006-05-18 00:33:32 +08: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 12:55:50 +08:00
|
|
|
#include "exec_cmd.h"
|
2006-05-20 16:28:49 +08:00
|
|
|
#include "cache-tree.h"
|
2007-09-18 08:06:44 +08:00
|
|
|
#include "run-command.h"
|
2007-10-04 05:45:02 +08:00
|
|
|
#include "parse-options.h"
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2007-10-04 05:45:02 +08:00
|
|
|
static const char * const builtin_add_usage[] = {
|
2008-07-13 21:36:15 +08:00
|
|
|
"git add [options] [--] <filepattern>...",
|
2007-10-04 05:45:02 +08:00
|
|
|
NULL
|
|
|
|
};
|
2007-11-25 21:15:42 +08:00
|
|
|
static int patch_interactive = 0, add_interactive = 0;
|
2007-05-12 14:42:00 +08:00
|
|
|
static int take_worktree_changes;
|
2007-02-28 11:31:10 +08: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 13:30:40 +08:00
|
|
|
static void fill_pathspec_matches(const char **pathspec, char *seen, int specs)
|
|
|
|
{
|
|
|
|
int num_unmatched = 0, i;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Since we are walking the index as if we are warlking the directory,
|
|
|
|
* 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-18 00:33:32 +08:00
|
|
|
static void prune_directory(struct dir_struct *dir, const char **pathspec, int prefix)
|
|
|
|
{
|
2006-05-18 04:23:19 +08:00
|
|
|
char *seen;
|
|
|
|
int i, specs;
|
2006-05-18 00:33:32 +08:00
|
|
|
struct dir_entry **src, **dst;
|
|
|
|
|
2006-05-18 04:23:19 +08:00
|
|
|
for (specs = 0; pathspec[specs]; specs++)
|
|
|
|
/* nothing */;
|
2006-07-25 15:30:18 +08:00
|
|
|
seen = xcalloc(specs, 1);
|
2006-05-18 04:23:19 +08:00
|
|
|
|
2006-05-18 00:33:32 +08:00
|
|
|
src = dst = dir->entries;
|
|
|
|
i = dir->nr;
|
|
|
|
while (--i >= 0) {
|
|
|
|
struct dir_entry *entry = *src++;
|
2006-12-30 03:01:31 +08:00
|
|
|
if (match_pathspec(pathspec, entry->name, entry->len,
|
|
|
|
prefix, seen))
|
|
|
|
*dst++ = entry;
|
2006-05-18 00:33:32 +08: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 13:30:40 +08:00
|
|
|
fill_pathspec_matches(pathspec, seen, specs);
|
2006-05-18 04:23:19 +08:00
|
|
|
|
|
|
|
for (i = 0; i < specs; 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-13 05:42:14 +08:00
|
|
|
if (!seen[i] && !file_exists(pathspec[i]))
|
|
|
|
die("pathspec '%s' did not match any files",
|
|
|
|
pathspec[i]);
|
2006-05-18 04:23:19 +08:00
|
|
|
}
|
2007-10-29 15:00:33 +08:00
|
|
|
free(seen);
|
2006-05-18 00:33:32 +08:00
|
|
|
}
|
|
|
|
|
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-13 05:42:14 +08:00
|
|
|
static void fill_directory(struct dir_struct *dir, const char **pathspec,
|
|
|
|
int ignored_too)
|
2006-05-18 00:33:32 +08:00
|
|
|
{
|
|
|
|
const char *path, *base;
|
|
|
|
int baselen;
|
|
|
|
|
|
|
|
/* Set up the default git porcelain excludes */
|
|
|
|
memset(dir, 0, sizeof(*dir));
|
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-13 05:42:14 +08:00
|
|
|
if (!ignored_too) {
|
|
|
|
dir->collect_ignored = 1;
|
core.excludesfile clean-up
There are inconsistencies in the way commands currently handle
the core.excludesfile configuration variable. The problem is
the variable is too new to be noticed by anything other than
git-add and git-status.
* git-ls-files does not notice any of the "ignore" files by
default, as it predates the standardized set of ignore files.
The calling scripts established the convention to use
.git/info/exclude, .gitignore, and later core.excludesfile.
* git-add and git-status know about it because they call
add_excludes_from_file() directly with their own notion of
which standard set of ignore files to use. This is just a
stupid duplication of code that need to be updated every time
the definition of the standard set of ignore files is
changed.
* git-read-tree takes --exclude-per-directory=<gitignore>,
not because the flexibility was needed. Again, this was
because the option predates the standardization of the ignore
files.
* git-merge-recursive uses hardcoded per-directory .gitignore
and nothing else. git-clean (scripted version) does not
honor core.* because its call to underlying ls-files does not
know about it. git-clean in C (parked in 'pu') doesn't either.
We probably could change git-ls-files to use the standard set
when no excludes are specified on the command line and ignore
processing was asked, or something like that, but that will be a
change in semantics and might break people's scripts in a subtle
way. I am somewhat reluctant to make such a change.
On the other hand, I think it makes perfect sense to fix
git-read-tree, git-merge-recursive and git-clean to follow the
same rule as other commands. I do not think of a valid use case
to give an exclude-per-directory that is nonstandard to
read-tree command, outside a "negative" test in the t1004 test
script.
This patch is the first step to untangle this mess.
The next step would be to teach read-tree, merge-recursive and
clean (in C) to use setup_standard_excludes().
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-11-14 16:05:00 +08:00
|
|
|
setup_standard_excludes(dir);
|
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-13 05:42:14 +08:00
|
|
|
}
|
2006-05-18 00:33:32 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Calculate common prefix for the pathspec, and
|
|
|
|
* use that to optimize the directory walk
|
|
|
|
*/
|
|
|
|
baselen = common_prefix(pathspec);
|
|
|
|
path = ".";
|
|
|
|
base = "";
|
2007-09-16 06:32:36 +08:00
|
|
|
if (baselen)
|
|
|
|
path = base = xmemdupz(*pathspec, baselen);
|
2006-05-18 00:33:32 +08:00
|
|
|
|
|
|
|
/* Read the directory and prune it */
|
Optimize directory listing with pathspec limiter.
The way things are set up, you can now pass a "pathspec" to the
"read_directory()" function. If you pass NULL, it acts exactly
like it used to do (read everything). If you pass a non-NULL
pointer, it will simplify it into a "these are the prefixes
without any special characters", and stop any readdir() early if
the path in question doesn't match any of the prefixes.
NOTE! This does *not* obviate the need for the caller to do the *exact*
pathspec match later. It's a first-level filter on "read_directory()", but
it does not do the full pathspec thing. Maybe it should. But in the
meantime, builtin-add.c really does need to do first
read_directory(dir, .., pathspec);
if (pathspec)
prune_directory(dir, pathspec, baselen);
ie the "prune_directory()" part will do the *exact* pathspec pruning,
while the "read_directory()" will use the pathspec just to do some quick
high-level pruning of the directories it will recurse into.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Junio C Hamano <junkio@cox.net>
2007-03-31 11:39:30 +08:00
|
|
|
read_directory(dir, path, base, baselen, pathspec);
|
2006-05-18 00:33:32 +08:00
|
|
|
if (pathspec)
|
|
|
|
prune_directory(dir, pathspec, baselen);
|
|
|
|
}
|
|
|
|
|
2007-08-12 05:59:01 +08: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);
|
2008-07-20 15:21:38 +08:00
|
|
|
refresh_index(&the_index, verbose ? REFRESH_SAY_CHANGED : REFRESH_QUIET,
|
|
|
|
pathspec, seen);
|
2007-08-12 05:59:01 +08:00
|
|
|
for (i = 0; i < specs; i++) {
|
|
|
|
if (!seen[i])
|
|
|
|
die("pathspec '%s' did not match any files", pathspec[i]);
|
|
|
|
}
|
2007-10-29 15:00:33 +08:00
|
|
|
free(seen);
|
2007-08-12 05:59:01 +08:00
|
|
|
}
|
|
|
|
|
2007-11-26 02:10:10 +08:00
|
|
|
static const char **validate_pathspec(int argc, const char **argv, const char *prefix)
|
|
|
|
{
|
|
|
|
const char **pathspec = get_pathspec(prefix, argv);
|
|
|
|
|
2008-08-04 15:52:37 +08:00
|
|
|
if (pathspec) {
|
|
|
|
const char **p;
|
|
|
|
for (p = pathspec; *p; p++) {
|
|
|
|
if (has_symlink_leading_path(strlen(*p), *p)) {
|
|
|
|
int len = prefix ? strlen(prefix) : 0;
|
|
|
|
die("'%s' is beyond a symbolic link", *p + len);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-11-26 02:10:10 +08:00
|
|
|
return pathspec;
|
|
|
|
}
|
|
|
|
|
|
|
|
int interactive_add(int argc, const char **argv, const char *prefix)
|
2007-09-18 08:06:44 +08:00
|
|
|
{
|
2007-11-25 21:15:42 +08:00
|
|
|
int status, ac;
|
2007-11-26 02:10:10 +08:00
|
|
|
const char **args;
|
|
|
|
const char **pathspec = NULL;
|
|
|
|
|
|
|
|
if (argc) {
|
|
|
|
pathspec = validate_pathspec(argc, argv, prefix);
|
|
|
|
if (!pathspec)
|
|
|
|
return -1;
|
|
|
|
}
|
2007-11-26 02:07:55 +08:00
|
|
|
|
2007-11-25 21:15:42 +08:00
|
|
|
args = xcalloc(sizeof(const char *), (argc + 4));
|
|
|
|
ac = 0;
|
|
|
|
args[ac++] = "add--interactive";
|
|
|
|
if (patch_interactive)
|
|
|
|
args[ac++] = "--patch";
|
|
|
|
args[ac++] = "--";
|
|
|
|
if (argc) {
|
|
|
|
memcpy(&(args[ac]), pathspec, sizeof(const char *) * argc);
|
|
|
|
ac += argc;
|
|
|
|
}
|
|
|
|
args[ac] = NULL;
|
2007-11-22 08:02:52 +08:00
|
|
|
|
|
|
|
status = run_command_v_opt(args, RUN_GIT_CMD);
|
|
|
|
free(args);
|
|
|
|
return status;
|
2007-09-18 08:06:44 +08:00
|
|
|
}
|
|
|
|
|
2006-06-07 03:51:49 +08:00
|
|
|
static struct lock_file lock_file;
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2007-08-29 06:41:23 +08:00
|
|
|
static const char ignore_error[] =
|
2006-12-26 09:46:38 +08:00
|
|
|
"The following paths are ignored by one of your .gitignore files:\n";
|
|
|
|
|
2007-10-04 05:45:02 +08:00
|
|
|
static int verbose = 0, show_only = 0, ignored_too = 0, refresh_only = 0;
|
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 10:51:11 +08:00
|
|
|
static int ignore_add_errors, addremove;
|
2007-10-04 05:45:02 +08: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 21:15:42 +08:00
|
|
|
OPT_BOOLEAN('p', "patch", &patch_interactive, "interactive patching"),
|
2008-06-14 17:48:00 +08:00
|
|
|
OPT_BOOLEAN('f', "force", &ignored_too, "allow adding otherwise ignored files"),
|
|
|
|
OPT_BOOLEAN('u', "update", &take_worktree_changes, "update tracked files"),
|
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 10:51:11 +08:00
|
|
|
OPT_BOOLEAN('A', "all", &addremove, "add all, noticing removal of tracked files"),
|
2007-10-04 05:45:02 +08:00
|
|
|
OPT_BOOLEAN( 0 , "refresh", &refresh_only, "don't add, only refresh the index"),
|
2008-05-13 01:58:29 +08:00
|
|
|
OPT_BOOLEAN( 0 , "ignore-errors", &ignore_add_errors, "just skip files which cannot be added because of errors"),
|
2007-10-04 05:45:02 +08:00
|
|
|
OPT_END(),
|
|
|
|
};
|
|
|
|
|
2008-05-26 05:25:02 +08:00
|
|
|
static int add_config(const char *var, const char *value, void *cb)
|
2008-05-13 01:59:23 +08:00
|
|
|
{
|
|
|
|
if (!strcasecmp(var, "add.ignore-errors")) {
|
|
|
|
ignore_add_errors = git_config_bool(var, value);
|
|
|
|
return 0;
|
|
|
|
}
|
2008-05-26 05:25:02 +08:00
|
|
|
return git_default_config(var, value, cb);
|
2008-05-13 01:59:23 +08:00
|
|
|
}
|
|
|
|
|
2008-07-20 10:22:25 +08: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 13:44:25 +08:00
|
|
|
int cmd_add(int argc, const char **argv, const char *prefix)
|
2006-05-18 00:33:32 +08:00
|
|
|
{
|
2008-05-13 01:58:10 +08:00
|
|
|
int exit_status = 0;
|
2008-07-20 10:22:25 +08:00
|
|
|
int newfd;
|
2006-05-18 00:33:32 +08:00
|
|
|
const char **pathspec;
|
|
|
|
struct dir_struct dir;
|
2008-05-23 05:59:42 +08:00
|
|
|
int flags;
|
2008-07-20 10:22:25 +08: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 12:55:50 +08:00
|
|
|
|
2007-10-04 05:45:02 +08:00
|
|
|
argc = parse_options(argc, argv, builtin_add_options,
|
|
|
|
builtin_add_usage, 0);
|
2007-11-25 21:15:42 +08:00
|
|
|
if (patch_interactive)
|
|
|
|
add_interactive = 1;
|
2007-11-22 08:02:52 +08:00
|
|
|
if (add_interactive)
|
2007-11-26 02:10:10 +08:00
|
|
|
exit(interactive_add(argc, argv, prefix));
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2008-05-26 05:25:02 +08:00
|
|
|
git_config(add_config, NULL);
|
2006-05-18 00:33:32 +08:00
|
|
|
|
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 10:51:11 +08: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 13:30:40 +08: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 10:51:11 +08:00
|
|
|
static const char *here[2] = { ".", NULL };
|
|
|
|
argc = 1;
|
|
|
|
argv = here;
|
|
|
|
}
|
|
|
|
|
2008-07-20 10:22:25 +08: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 14:09:02 +08:00
|
|
|
newfd = hold_locked_index(&lock_file, 1);
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2008-05-23 05:59:42 +08:00
|
|
|
flags = ((verbose ? ADD_CACHE_VERBOSE : 0) |
|
2008-05-26 05:03:50 +08:00
|
|
|
(show_only ? ADD_CACHE_PRETEND : 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 13:30:40 +08:00
|
|
|
(ignore_add_errors ? ADD_CACHE_IGNORE_ERRORS : 0) |
|
|
|
|
(!(addremove || take_worktree_changes)
|
|
|
|
? ADD_CACHE_IGNORE_REMOVAL : 0));
|
2008-05-23 05:59:42 +08:00
|
|
|
|
2008-07-20 10:22:25 +08:00
|
|
|
if (require_pathspec && argc == 0) {
|
2006-12-21 05:06:46 +08:00
|
|
|
fprintf(stderr, "Nothing specified, nothing added.\n");
|
|
|
|
fprintf(stderr, "Maybe you wanted to say 'git add .'?\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2008-08-04 15:52:37 +08:00
|
|
|
pathspec = validate_pathspec(argc, argv, prefix);
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2006-12-05 00:13:39 +08:00
|
|
|
if (read_cache() < 0)
|
|
|
|
die("index file corrupt");
|
|
|
|
|
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 13:30:40 +08:00
|
|
|
if (add_new_files)
|
|
|
|
/* This picks up the paths that are not tracked */
|
|
|
|
fill_directory(&dir, pathspec, ignored_too);
|
|
|
|
|
2008-07-20 10:22:25 +08:00
|
|
|
if (refresh_only) {
|
|
|
|
refresh(verbose, pathspec);
|
|
|
|
goto finish;
|
2006-12-26 09:46:38 +08: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 13:30:40 +08:00
|
|
|
exit_status |= add_files_to_cache(prefix, pathspec, flags);
|
2008-07-20 10:22:25 +08:00
|
|
|
|
|
|
|
if (add_new_files)
|
|
|
|
exit_status |= add_files(&dir, flags);
|
2006-05-18 00:33:32 +08:00
|
|
|
|
2007-04-20 16:39:39 +08:00
|
|
|
finish:
|
2006-05-18 00:33:32 +08:00
|
|
|
if (active_cache_changed) {
|
|
|
|
if (write_cache(newfd, active_cache, active_nr) ||
|
2008-01-17 03:12:46 +08:00
|
|
|
commit_locked_index(&lock_file))
|
2006-05-18 00:33:32 +08:00
|
|
|
die("Unable to write new index file");
|
|
|
|
}
|
|
|
|
|
2008-05-13 01:58:10 +08:00
|
|
|
return exit_status;
|
2006-05-18 00:33:32 +08:00
|
|
|
}
|