Skip to content

Commit 76a3f28

Browse files
pks-tgitster
authored andcommitted
builtin/history: perform revwalk checks before asking for user input
When setting up the revision walk in git-history(1) we also perform some verifications whether the request actually looks sane. Unfortunately, these verifications come _after_ we have already asked the user for the commit message of the commit that is to be rewritten. So in case any of the verifications fails, the user will have lost their modifications. Extract the function to set up the revision walk and call it before we ask for user input to fix this. Adapt one of the tests that is expected to fail because of this check to use false(1) as editor. If the editor had been executed by Git, it would fail with the error message "Aborting commit as launching the editor failed." Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 453e7b7 commit 76a3f28

2 files changed

Lines changed: 44 additions & 27 deletions

File tree

builtin/history.c

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -177,30 +177,15 @@ static int parse_ref_action(const struct option *opt, const char *value, int uns
177177
return 0;
178178
}
179179

180-
static int handle_reference_updates(enum ref_action action,
181-
struct repository *repo,
182-
struct commit *original,
183-
struct commit *rewritten,
184-
const char *reflog_msg)
180+
static int setup_revwalk(struct repository *repo,
181+
enum ref_action action,
182+
struct commit *original,
183+
struct rev_info *revs)
185184
{
186-
const struct name_decoration *decoration;
187-
struct replay_revisions_options opts = { 0 };
188-
struct replay_result result = { 0 };
189-
struct ref_transaction *transaction = NULL;
190185
struct strvec args = STRVEC_INIT;
191-
struct strbuf err = STRBUF_INIT;
192-
struct commit *head = NULL;
193-
struct rev_info revs;
194-
char hex[GIT_MAX_HEXSZ + 1];
195-
bool detached_head;
196-
int head_flags = 0;
197186
int ret;
198187

199-
refs_read_ref_full(get_main_ref_store(repo), "HEAD",
200-
RESOLVE_REF_NO_RECURSE, NULL, &head_flags);
201-
detached_head = !(head_flags & REF_ISSYMREF);
202-
203-
repo_init_revisions(repo, &revs, NULL);
188+
repo_init_revisions(repo, revs, NULL);
204189
strvec_push(&args, "ignored");
205190
strvec_push(&args, "--reverse");
206191
strvec_push(&args, "--topo-order");
@@ -224,6 +209,7 @@ static int handle_reference_updates(enum ref_action action,
224209
*/
225210
if (action == REF_ACTION_HEAD) {
226211
struct commit_list *from_list = NULL;
212+
struct commit *head;
227213

228214
head = lookup_commit_reference_by_name("HEAD");
229215
if (!head) {
@@ -250,20 +236,47 @@ static int handle_reference_updates(enum ref_action action,
250236
strvec_push(&args, "HEAD");
251237
}
252238

253-
setup_revisions_from_strvec(&args, &revs, NULL);
239+
setup_revisions_from_strvec(&args, revs, NULL);
254240
if (args.nr != 1)
255241
BUG("revisions were set up with invalid argument");
256242

243+
ret = 0;
244+
245+
out:
246+
strvec_clear(&args);
247+
return ret;
248+
}
249+
250+
static int handle_reference_updates(struct rev_info *revs,
251+
enum ref_action action,
252+
struct commit *original,
253+
struct commit *rewritten,
254+
const char *reflog_msg)
255+
{
256+
const struct name_decoration *decoration;
257+
struct replay_revisions_options opts = { 0 };
258+
struct replay_result result = { 0 };
259+
struct ref_transaction *transaction = NULL;
260+
struct strbuf err = STRBUF_INIT;
261+
char hex[GIT_MAX_HEXSZ + 1];
262+
bool detached_head;
263+
int head_flags = 0;
264+
int ret;
265+
266+
refs_read_ref_full(get_main_ref_store(revs->repo), "HEAD",
267+
RESOLVE_REF_NO_RECURSE, NULL, &head_flags);
268+
detached_head = !(head_flags & REF_ISSYMREF);
269+
257270
opts.onto = oid_to_hex_r(hex, &rewritten->object.oid);
258271

259-
ret = replay_revisions(&revs, &opts, &result);
272+
ret = replay_revisions(revs, &opts, &result);
260273
if (ret)
261274
goto out;
262275

263276
switch (action) {
264277
case REF_ACTION_BRANCHES:
265278
case REF_ACTION_HEAD:
266-
transaction = ref_store_transaction_begin(get_main_ref_store(repo), 0, &err);
279+
transaction = ref_store_transaction_begin(get_main_ref_store(revs->repo), 0, &err);
267280
if (!transaction) {
268281
ret = error(_("failed to begin ref transaction: %s"), err.buf);
269282
goto out;
@@ -343,9 +356,7 @@ static int handle_reference_updates(enum ref_action action,
343356
out:
344357
ref_transaction_free(transaction);
345358
replay_result_release(&result);
346-
release_revisions(&revs);
347359
strbuf_release(&err);
348-
strvec_clear(&args);
349360
return ret;
350361
}
351362

@@ -367,6 +378,7 @@ static int cmd_history_reword(int argc,
367378
};
368379
struct strbuf reflog_msg = STRBUF_INIT;
369380
struct commit *original, *rewritten;
381+
struct rev_info revs;
370382
int ret;
371383

372384
argc = parse_options(argc, argv, prefix, options, usage, 0);
@@ -385,6 +397,10 @@ static int cmd_history_reword(int argc,
385397
goto out;
386398
}
387399

400+
ret = setup_revwalk(repo, action, original, &revs);
401+
if (ret)
402+
goto out;
403+
388404
ret = commit_tree_with_edited_message(repo, "reworded", original, &rewritten);
389405
if (ret < 0) {
390406
ret = error(_("failed writing reworded commit"));
@@ -393,7 +409,7 @@ static int cmd_history_reword(int argc,
393409

394410
strbuf_addf(&reflog_msg, "reword: updating %s", argv[0]);
395411

396-
ret = handle_reference_updates(action, repo, original, rewritten,
412+
ret = handle_reference_updates(&revs, action, original, rewritten,
397413
reflog_msg.buf);
398414
if (ret < 0) {
399415
ret = error(_("failed replaying descendants"));
@@ -404,6 +420,7 @@ static int cmd_history_reword(int argc,
404420

405421
out:
406422
strbuf_release(&reflog_msg);
423+
release_revisions(&revs);
407424
return ret;
408425
}
409426

t/t3451-history-reword.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ test_expect_success '--ref-action=head updates only HEAD' '
263263
264264
# When told to update HEAD, only, the command will refuse to
265265
# rewrite commits that are not an ancestor of HEAD.
266-
test_must_fail git history reword --ref-action=head theirs 2>err &&
266+
test_must_fail git -c core.editor=false history reword --ref-action=head theirs 2>err &&
267267
test_grep "rewritten commit must be an ancestor of HEAD" err &&
268268
269269
reword_with_message --ref-action=head base >updates <<-\EOF &&

0 commit comments

Comments
 (0)