git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
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 4/8] built-in add -i: re-implement `revert` in C
Date: Fri, 15 Nov 2019 12:36:18 +0000	[thread overview]
Message-ID: <5c31bbd24ab937f5906f967f007d5bcd305779e2.1573821382.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.171.git.1573821382.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 b0bda0cd2d..191a10b97d 100644
--- a/add-interactive.c
+++ b/add-interactive.c
@@ -653,6 +653,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)
@@ -748,6 +856,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


  parent reply	other threads:[~2019-11-15 12:36 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 ` Johannes Schindelin via GitGitGadget [this message]
2019-11-15 12:36 ` [PATCH 5/8] built-in add -i: re-implement `add-untracked` in C 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   ` [PATCH v2 5/9] built-in add -i: re-implement `revert` in C Johannes Schindelin via GitGitGadget
2019-11-29 21:11   ` [PATCH v2 6/9] built-in add -i: re-implement `add-untracked` " 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

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=5c31bbd24ab937f5906f967f007d5bcd305779e2.1573821382.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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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 read-only IMAP folder(s) and NNTP newsgroup(s).