@ -8,6 +8,7 @@
@@ -8,6 +8,7 @@
#include "string-list.h"
#include "lockfile.h"
#include "dir.h"
#include "run-command.h"
struct add_i_state {
struct repository *r;
@ -375,7 +376,7 @@ static ssize_t list_and_choose(struct add_i_state *s,
@@ -375,7 +376,7 @@ static ssize_t list_and_choose(struct add_i_state *s,
struct adddel {
uintmax_t add, del;
unsigned seen:1, binary:1;
unsigned seen:1, unmerged:1, binary:1;
};
struct file_item {
@ -415,6 +416,7 @@ struct collection_status {
@@ -415,6 +416,7 @@ struct collection_status {
const char *reference;
unsigned skip_unseen:1;
size_t unmerged_count, binary_count;
struct string_list *files;
struct hashmap file_map;
};
@ -437,7 +439,7 @@ static void collect_changes_cb(struct diff_queue_struct *q,
@@ -437,7 +439,7 @@ static void collect_changes_cb(struct diff_queue_struct *q,
int hash = strhash(name);
struct pathname_entry *entry;
struct file_item *file_item;
struct adddel *adddel;
struct adddel *adddel, *other_adddel;
entry = hashmap_get_entry_from_hash(&s->file_map, hash, name,
struct pathname_entry, ent);
@ -457,11 +459,21 @@ static void collect_changes_cb(struct diff_queue_struct *q,
@@ -457,11 +459,21 @@ static void collect_changes_cb(struct diff_queue_struct *q,
file_item = entry->item;
adddel = s->mode == FROM_INDEX ?
&file_item->index : &file_item->worktree;
other_adddel = s->mode == FROM_INDEX ?
&file_item->worktree : &file_item->index;
adddel->seen = 1;
adddel->add = stat.files[i]->added;
adddel->del = stat.files[i]->deleted;
if (stat.files[i]->is_binary)
if (stat.files[i]->is_binary) {
if (!other_adddel->binary)
s->binary_count++;
adddel->binary = 1;
}
if (stat.files[i]->is_unmerged) {
if (!other_adddel->unmerged)
s->unmerged_count++;
adddel->unmerged = 1;
}
}
free_diffstat_info(&stat);
}
@ -475,7 +487,9 @@ enum modified_files_filter {
@@ -475,7 +487,9 @@ enum modified_files_filter {
static int get_modified_files(struct repository *r,
enum modified_files_filter filter,
struct prefix_item_list *files,
const struct pathspec *ps)
const struct pathspec *ps,
size_t *unmerged_count,
size_t *binary_count)
{
struct object_id head_oid;
int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
@ -525,6 +539,10 @@ static int get_modified_files(struct repository *r,
@@ -525,6 +539,10 @@ static int get_modified_files(struct repository *r,
clear_pathspec(&rev.prune_data);
}
hashmap_free_entries(&s.file_map, struct pathname_entry, ent);
if (unmerged_count)
*unmerged_count = s.unmerged_count;
if (binary_count)
*binary_count = s.binary_count;
/* While the diffs are ordered already, we ran *two* diffs... */
string_list_sort(&files->items);
@ -607,7 +625,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps,
@@ -607,7 +625,7 @@ static int run_status(struct add_i_state *s, const struct pathspec *ps,
struct prefix_item_list *files,
struct list_and_choose_options *opts)
{
if (get_modified_files(s->r, NO_FILTER, files, ps) < 0)
if (get_modified_files(s->r, NO_FILTER, files, ps, NULL, NULL) < 0)
return -1;
list(s, &files->items, NULL, &opts->list_opts);
@ -624,7 +642,7 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
@@ -624,7 +642,7 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
size_t count, i;
struct lock_file index_lock;
if (get_modified_files(s->r, WORKTREE_ONLY, files, ps) < 0)
if (get_modified_files(s->r, WORKTREE_ONLY, files, ps, NULL, NULL) < 0)
return -1;
if (!files->items.nr) {
@ -703,7 +721,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps,
@@ -703,7 +721,7 @@ static int run_revert(struct add_i_state *s, const struct pathspec *ps,
struct tree *tree;
struct diff_options diffopt = { NULL };
if (get_modified_files(s->r, INDEX_ONLY, files, ps) < 0)
if (get_modified_files(s->r, INDEX_ONLY, files, ps, NULL, NULL) < 0)
return -1;
if (!files->items.nr) {
@ -855,6 +873,64 @@ finish_add_untracked:
@@ -855,6 +873,64 @@ finish_add_untracked:
return res;
}
static int run_patch(struct add_i_state *s, const struct pathspec *ps,
struct prefix_item_list *files,
struct list_and_choose_options *opts)
{
int res = 0;
ssize_t count, i, j;
size_t unmerged_count = 0, binary_count = 0;
if (get_modified_files(s->r, WORKTREE_ONLY, files, ps,
&unmerged_count, &binary_count) < 0)
return -1;
if (unmerged_count || binary_count) {
for (i = j = 0; i < files->items.nr; i++) {
struct file_item *item = files->items.items[i].util;
if (item->index.binary || item->worktree.binary) {
free(item);
free(files->items.items[i].string);
} else if (item->index.unmerged ||
item->worktree.unmerged) {
color_fprintf_ln(stderr, s->error_color,
_("ignoring unmerged: %s"),
files->items.items[i].string);
free(item);
free(files->items.items[i].string);
} else
files->items.items[j++] = files->items.items[i];
}
files->items.nr = j;
}
if (!files->items.nr) {
if (binary_count)
fprintf(stderr, _("Only binary files changed.\n"));
else
fprintf(stderr, _("No changes.\n"));
return 0;
}
opts->prompt = N_("Patch update");
count = list_and_choose(s, files, opts);
if (count >= 0) {
struct argv_array args = ARGV_ARRAY_INIT;
argv_array_pushl(&args, "git", "add--interactive", "--patch",
"--", NULL);
for (i = 0; i < files->items.nr; i++)
if (files->selected[i])
argv_array_push(&args,
files->items.items[i].string);
res = run_command_v_opt(args.argv, 0);
argv_array_clear(&args);
}
return res;
}
static int run_help(struct add_i_state *s, const struct pathspec *unused_ps,
struct prefix_item_list *unused_files,
struct list_and_choose_options *unused_opts)
@ -952,6 +1028,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
@@ -952,6 +1028,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
{ "update", run_update },
{ "revert", run_revert },
{ "add untracked", run_add_untracked },
{ "patch", run_patch },
{ "help", run_help },
};
struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;