From: "Johannes Schindelin via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: Johannes Schindelin <johannes.schindelin@gmx.de>,
Junio C Hamano <gitster@pobox.com>,
Johannes Schindelin <johannes.schindelin@gmx.de>
Subject: [PATCH v2 5/9] built-in add -i: re-implement `revert` in C
Date: Fri, 29 Nov 2019 21:11:45 +0000 [thread overview]
Message-ID: <f70723a160c1ecddf87349fc99af25f7718e1413.1575061909.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.171.v2.git.1575061909.gitgitgadget@gmail.com>
From: Johannes Schindelin <johannes.schindelin@gmx.de>
This is a relatively straight-forward port from the Perl version, with
the notable exception that we imitate `git reset -- <paths>` in the C
version rather than the convoluted `git ls-tree HEAD -- <paths> | git
update-index --index-info` followed by `git update-index --force-remove
-- <paths>` for the missed ones.
While at it, we fix the pretty obvious bug where the `revert` command
offers to unstage files that do not have staged changes.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
add-interactive.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/add-interactive.c b/add-interactive.c
index 1e34e88069..adab17a635 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -657,6 +657,114 @@ static int run_update(struct add_i_state *s, const struct pathspec *ps,
return res;
}
+static void revert_from_diff(struct diff_queue_struct *q,
+ struct diff_options *opt, void *data)
+{
+ int i, add_flags = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
+
+ for (i = 0; i < q->nr; i++) {
+ struct diff_filespec *one = q->queue[i]->one;
+ struct cache_entry *ce;
+
+ if (!(one->mode && !is_null_oid(&one->oid))) {
+ remove_file_from_index(opt->repo->index, one->path);
+ printf(_("note: %s is untracked now.\n"), one->path);
+ } else {
+ ce = make_cache_entry(opt->repo->index, one->mode,
+ &one->oid, one->path, 0, 0);
+ if (!ce)
+ die(_("make_cache_entry failed for path '%s'"),
+ one->path);
+ add_index_entry(opt->repo->index, ce, add_flags);
+ }
+ }
+}
+
+static int run_revert(struct add_i_state *s, const struct pathspec *ps,
+ struct prefix_item_list *files,
+ struct list_and_choose_options *opts)
+{
+ int res = 0, fd;
+ size_t count, i, j;
+
+ struct object_id oid;
+ int is_initial = !resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &oid,
+ NULL);
+ struct lock_file index_lock;
+ const char **paths;
+ struct tree *tree;
+ struct diff_options diffopt = { NULL };
+
+ if (get_modified_files(s->r, INDEX_ONLY, files, ps) < 0)
+ return -1;
+
+ if (!files->items.nr) {
+ putchar('\n');
+ return 0;
+ }
+
+ opts->prompt = N_("Revert");
+ count = list_and_choose(s, files, opts);
+ if (count <= 0)
+ goto finish_revert;
+
+ fd = repo_hold_locked_index(s->r, &index_lock, LOCK_REPORT_ON_ERROR);
+ if (fd < 0) {
+ res = -1;
+ goto finish_revert;
+ }
+
+ if (is_initial)
+ oidcpy(&oid, s->r->hash_algo->empty_tree);
+ else {
+ tree = parse_tree_indirect(&oid);
+ if (!tree) {
+ res = error(_("Could not parse HEAD^{tree}"));
+ goto finish_revert;
+ }
+ oidcpy(&oid, &tree->object.oid);
+ }
+
+ ALLOC_ARRAY(paths, count + 1);
+ for (i = j = 0; i < files->items.nr; i++)
+ if (files->selected[i])
+ paths[j++] = files->items.items[i].string;
+ paths[j] = NULL;
+
+ parse_pathspec(&diffopt.pathspec, 0,
+ PATHSPEC_PREFER_FULL | PATHSPEC_LITERAL_PATH,
+ NULL, paths);
+
+ diffopt.output_format = DIFF_FORMAT_CALLBACK;
+ diffopt.format_callback = revert_from_diff;
+ diffopt.flags.override_submodule_config = 1;
+ diffopt.repo = s->r;
+
+ if (do_diff_cache(&oid, &diffopt))
+ res = -1;
+ else {
+ diffcore_std(&diffopt);
+ diff_flush(&diffopt);
+ }
+ free(paths);
+ clear_pathspec(&diffopt.pathspec);
+
+ if (!res && write_locked_index(s->r->index, &index_lock,
+ COMMIT_LOCK) < 0)
+ res = -1;
+ else
+ res = repo_refresh_and_write_index(s->r, REFRESH_QUIET, 0, 1,
+ NULL, NULL, NULL);
+
+ if (!res)
+ printf(Q_("reverted %d path\n",
+ "reverted %d paths\n", count), (int)count);
+
+finish_revert:
+ putchar('\n');
+ 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)
@@ -752,6 +860,7 @@ int run_add_i(struct repository *r, const struct pathspec *ps)
} command_list[] = {
{ "status", run_status },
{ "update", run_update },
+ { "revert", run_revert },
{ "help", run_help },
};
struct prefix_item_list commands = PREFIX_ITEM_LIST_INIT;
--
gitgitgadget
next prev parent reply other threads:[~2019-11-29 21:12 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-11-15 12:36 [PATCH 0/8] build-in add -i: implement all commands in the main loop Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 1/8] built-in add -i: allow filtering the modified files list Johannes Schindelin via GitGitGadget
2019-11-21 8:06 ` Junio C Hamano
2019-11-25 15:20 ` Johannes Schindelin
2019-11-15 12:36 ` [PATCH 2/8] built-in add -i: prepare for multi-selection commands Johannes Schindelin via GitGitGadget
2019-11-21 8:12 ` Junio C Hamano
2019-11-25 15:21 ` Johannes Schindelin
2019-11-15 12:36 ` [PATCH 3/8] built-in add -i: implement the `update` command Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 4/8] built-in add -i: re-implement `revert` in C Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 5/8] built-in add -i: re-implement `add-untracked` " Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 6/8] built-in add -i: implement the `patch` command Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 7/8] built-in add -i: re-implement the `diff` command Johannes Schindelin via GitGitGadget
2019-11-15 12:36 ` [PATCH 8/8] built-in add -i: offer the `quit` command Johannes Schindelin via GitGitGadget
2019-11-18 2:17 ` [PATCH 0/8] build-in add -i: implement all commands in the main loop Junio C Hamano
2019-11-18 2:22 ` Junio C Hamano
2019-11-18 19:22 ` Johannes Schindelin
2019-11-18 2:27 ` Junio C Hamano
2019-11-18 18:53 ` Johannes Schindelin
2019-11-19 1:29 ` Junio C Hamano
2019-11-29 21:11 ` [PATCH v2 0/9] built-in " Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 1/9] add-interactive: make sure to release `rev.prune_data` Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 2/9] built-in add -i: allow filtering the modified files list Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 3/9] built-in add -i: prepare for multi-selection commands Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 4/9] built-in add -i: implement the `update` command Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` Johannes Schindelin via GitGitGadget [this message]
2019-11-29 21:11 ` [PATCH v2 6/9] built-in add -i: re-implement `add-untracked` in C Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 7/9] built-in add -i: implement the `patch` command Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 8/9] built-in add -i: re-implement the `diff` command Johannes Schindelin via GitGitGadget
2019-11-29 21:11 ` [PATCH v2 9/9] built-in add -i: offer the `quit` command Johannes Schindelin via GitGitGadget
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=f70723a160c1ecddf87349fc99af25f7718e1413.1575061909.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=johannes.schindelin@gmx.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).