summaryrefslogtreecommitdiffstats
path: root/add-interactive.c
diff options
context:
space:
mode:
Diffstat (limited to 'add-interactive.c')
-rw-r--r--add-interactive.c91
1 files changed, 84 insertions, 7 deletions
diff --git a/add-interactive.c b/add-interactive.c
index a719d30b0b..cba9688bb5 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -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,
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 {
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,
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,
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 {
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,
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,
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,
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,
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:
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)
{ "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;