Skip to content

Commit 671451d

Browse files
phillipwoodgitster
authored andcommitted
status: improve rebase todo list parsing
When there is rebase in progress "git status" displays the last couple of completed and the next couple of pending commands from the todo list. When it does this is tries to abbreviate the object ids of the commits to be picked. Unfortunately it does not abbreviate the object ids when the line starts with "fixup -C" or "merge -C". It also mistakenly replaces the refname in "reset main" and "update-ref refs/heads/main" with the object id that the ref points to. Use the function added in the last commit to parse the command name and only try to abbreviate the argument for commands that take an object id. When trying to abbreviate an object id, only replace the object name if it starts with the abbreviated object id so that labels or branch names that contain only hex digits are left unchanged. Comments are now processed after stripping any leading whitespace from the line. This matches what the sequencer does in parse_insn_line(). The existing test cases are updated to test a wider variety of commands. Only the pending commands in the tests are changed to avoid removing existing coverage. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a8101ec commit 671451d

2 files changed

Lines changed: 141 additions & 50 deletions

File tree

t/t7512-status-help.sh

Lines changed: 48 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ test_expect_success 'status when splitting a commit' '
224224
COMMIT3=$(git rev-parse --short split_commit) &&
225225
test_commit four_split main.txt four &&
226226
COMMIT4=$(git rev-parse --short split_commit) &&
227-
FAKE_LINES="1 edit 2 3" &&
227+
FAKE_LINES="reword 1 edit 2 fixup_-C 3" &&
228228
export FAKE_LINES &&
229229
test_when_finished "git rebase --abort" &&
230230
ONTO=$(git rev-parse --short HEAD~3) &&
@@ -233,10 +233,10 @@ test_expect_success 'status when splitting a commit' '
233233
cat >expected <<EOF &&
234234
interactive rebase in progress; onto $ONTO
235235
Last commands done (2 commands done):
236-
pick $COMMIT2 # two_split
236+
reword $COMMIT2 # two_split
237237
edit $COMMIT3 # three_split
238238
Next command to do (1 remaining command):
239-
pick $COMMIT4 # four_split
239+
fixup -C $COMMIT4 # four_split
240240
(use "git rebase --edit-todo" to view and edit)
241241
You are currently splitting a commit while rebasing branch '\''split_commit'\'' on '\''$ONTO'\''.
242242
(Once your working directory is clean, run "git rebase --continue")
@@ -297,7 +297,7 @@ test_expect_success 'prepare for several edits' '
297297

298298

299299
test_expect_success 'status: (continue first edit) second edit' '
300-
FAKE_LINES="edit 1 edit 2 3" &&
300+
FAKE_LINES="edit 1 edit 2 drop 3" &&
301301
export FAKE_LINES &&
302302
test_when_finished "git rebase --abort" &&
303303
COMMIT2=$(git rev-parse --short several_edits^^) &&
@@ -312,7 +312,7 @@ Last commands done (2 commands done):
312312
edit $COMMIT2 # two_edits
313313
edit $COMMIT3 # three_edits
314314
Next command to do (1 remaining command):
315-
pick $COMMIT4 # four_edits
315+
drop $COMMIT4 # four_edits
316316
(use "git rebase --edit-todo" to view and edit)
317317
You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
318318
(use "git commit --amend" to amend the current commit)
@@ -327,7 +327,7 @@ EOF
327327

328328
test_expect_success 'status: (continue first edit) second edit and split' '
329329
git reset --hard several_edits &&
330-
FAKE_LINES="edit 1 edit 2 3" &&
330+
FAKE_LINES="edit 1 edit 2 squash 3" &&
331331
export FAKE_LINES &&
332332
test_when_finished "git rebase --abort" &&
333333
COMMIT2=$(git rev-parse --short several_edits^^) &&
@@ -343,7 +343,7 @@ Last commands done (2 commands done):
343343
edit $COMMIT2 # two_edits
344344
edit $COMMIT3 # three_edits
345345
Next command to do (1 remaining command):
346-
pick $COMMIT4 # four_edits
346+
squash $COMMIT4 # four_edits
347347
(use "git rebase --edit-todo" to view and edit)
348348
You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
349349
(Once your working directory is clean, run "git rebase --continue")
@@ -362,7 +362,7 @@ EOF
362362

363363
test_expect_success 'status: (continue first edit) second edit and amend' '
364364
git reset --hard several_edits &&
365-
FAKE_LINES="edit 1 edit 2 3" &&
365+
FAKE_LINES="edit 1 edit 2 fixup 3" &&
366366
export FAKE_LINES &&
367367
test_when_finished "git rebase --abort" &&
368368
COMMIT2=$(git rev-parse --short several_edits^^) &&
@@ -378,7 +378,7 @@ Last commands done (2 commands done):
378378
edit $COMMIT2 # two_edits
379379
edit $COMMIT3 # three_edits
380380
Next command to do (1 remaining command):
381-
pick $COMMIT4 # four_edits
381+
fixup $COMMIT4 # four_edits
382382
(use "git rebase --edit-todo" to view and edit)
383383
You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
384384
(use "git commit --amend" to amend the current commit)
@@ -393,7 +393,7 @@ EOF
393393

394394
test_expect_success 'status: (amend first edit) second edit' '
395395
git reset --hard several_edits &&
396-
FAKE_LINES="edit 1 edit 2 3" &&
396+
FAKE_LINES="edit 1 edit 2 fixup_-c 3" &&
397397
export FAKE_LINES &&
398398
test_when_finished "git rebase --abort" &&
399399
COMMIT2=$(git rev-parse --short several_edits^^) &&
@@ -409,7 +409,7 @@ Last commands done (2 commands done):
409409
edit $COMMIT2 # two_edits
410410
edit $COMMIT3 # three_edits
411411
Next command to do (1 remaining command):
412-
pick $COMMIT4 # four_edits
412+
fixup -c $COMMIT4 # four_edits
413413
(use "git rebase --edit-todo" to view and edit)
414414
You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
415415
(use "git commit --amend" to amend the current commit)
@@ -460,14 +460,20 @@ EOF
460460

461461
test_expect_success 'status: (amend first edit) second edit and amend' '
462462
git reset --hard several_edits &&
463-
FAKE_LINES="edit 1 edit 2 3" &&
464-
export FAKE_LINES &&
465463
test_when_finished "git rebase --abort" &&
466464
COMMIT2=$(git rev-parse --short several_edits^^) &&
467465
COMMIT3=$(git rev-parse --short several_edits^) &&
468466
COMMIT4=$(git rev-parse --short several_edits) &&
469467
ONTO=$(git rev-parse --short HEAD~3) &&
470-
git rebase -i HEAD~3 &&
468+
cat >todo <<-EOF &&
469+
edit several_edits^^ # two_edits
470+
edit several_edits^ # three_edits
471+
merge $(git rev-parse main) $(git rev-parse several_edits)
472+
EOF
473+
(
474+
set_replace_editor todo &&
475+
git rebase -i HEAD~3
476+
) &&
471477
git commit --amend -m "c" &&
472478
git rebase --continue &&
473479
git commit --amend -m "d" &&
@@ -477,7 +483,7 @@ Last commands done (2 commands done):
477483
edit $COMMIT2 # two_edits
478484
edit $COMMIT3 # three_edits
479485
Next command to do (1 remaining command):
480-
pick $COMMIT4 # four_edits
486+
merge $(git rev-parse --short main) $COMMIT4
481487
(use "git rebase --edit-todo" to view and edit)
482488
You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
483489
(use "git commit --amend" to amend the current commit)
@@ -525,14 +531,21 @@ EOF
525531

526532
test_expect_success 'status: (split first edit) second edit and split' '
527533
git reset --hard several_edits &&
528-
FAKE_LINES="edit 1 edit 2 3" &&
529-
export FAKE_LINES &&
530534
test_when_finished "git rebase --abort" &&
531535
COMMIT2=$(git rev-parse --short several_edits^^) &&
532536
COMMIT3=$(git rev-parse --short several_edits^) &&
533537
COMMIT4=$(git rev-parse --short several_edits) &&
538+
cat >todo <<-EOF &&
539+
edit several_edits^^ # two_edits
540+
edit several_edits^ # three_edits
541+
reset $(git rev-parse main)
542+
merge -C several_edits topic # title
543+
EOF
534544
ONTO=$(git rev-parse --short HEAD~3) &&
535-
git rebase -i HEAD~3 &&
545+
(
546+
set_replace_editor todo &&
547+
git rebase -i HEAD~3
548+
) &&
536549
git reset HEAD^ &&
537550
git add main.txt &&
538551
git commit --amend -m "f" &&
@@ -543,8 +556,9 @@ interactive rebase in progress; onto $ONTO
543556
Last commands done (2 commands done):
544557
edit $COMMIT2 # two_edits
545558
edit $COMMIT3 # three_edits
546-
Next command to do (1 remaining command):
547-
pick $COMMIT4 # four_edits
559+
Next commands to do (2 remaining commands):
560+
reset $(git rev-parse --short main)
561+
merge -C $COMMIT4 topic # title
548562
(use "git rebase --edit-todo" to view and edit)
549563
You are currently splitting a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
550564
(Once your working directory is clean, run "git rebase --continue")
@@ -563,14 +577,21 @@ EOF
563577

564578
test_expect_success 'status: (split first edit) second edit and amend' '
565579
git reset --hard several_edits &&
566-
FAKE_LINES="edit 1 edit 2 3" &&
567-
export FAKE_LINES &&
568580
test_when_finished "git rebase --abort" &&
581+
git branch cafe main &&
569582
COMMIT2=$(git rev-parse --short several_edits^^) &&
570583
COMMIT3=$(git rev-parse --short several_edits^) &&
571-
COMMIT4=$(git rev-parse --short several_edits) &&
584+
cat >todo <<-EOF &&
585+
edit several_edits^^ # two_edits
586+
edit several_edits^ # three_edits
587+
update-ref refs/heads/main
588+
reset cafe
589+
EOF
572590
ONTO=$(git rev-parse --short HEAD~3) &&
573-
git rebase -i HEAD~3 &&
591+
(
592+
set_replace_editor todo &&
593+
git rebase -i HEAD~3
594+
) &&
574595
git reset HEAD^ &&
575596
git add main.txt &&
576597
git commit --amend -m "g" &&
@@ -581,8 +602,9 @@ interactive rebase in progress; onto $ONTO
581602
Last commands done (2 commands done):
582603
edit $COMMIT2 # two_edits
583604
edit $COMMIT3 # three_edits
584-
Next command to do (1 remaining command):
585-
pick $COMMIT4 # four_edits
605+
Next commands to do (2 remaining commands):
606+
update-ref refs/heads/main
607+
reset cafe
586608
(use "git rebase --edit-todo" to view and edit)
587609
You are currently editing a commit while rebasing branch '\''several_edits'\'' on '\''$ONTO'\''.
588610
(use "git commit --amend" to amend the current commit)

wt-status.c

Lines changed: 93 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,35 +1365,108 @@ static int split_commit_in_progress(struct wt_status *s)
13651365
return split_in_progress;
13661366
}
13671367

1368+
static void abbrev_oid_in_line(struct repository *r,
1369+
struct strbuf *line, char **pp)
1370+
{
1371+
char *p = *pp;
1372+
char *end_of_object_name, saved;
1373+
const char *abbrev;
1374+
struct object_id oid;
1375+
bool have_oid;
1376+
1377+
p += strspn(p, " \t");
1378+
end_of_object_name = p + strcspn(p, " \t");
1379+
/*
1380+
* The for "merge" and "reset" the object name may be a label or
1381+
* ref rather than a hex object id. Only abbreviate the object
1382+
* name if it is a hex object id.
1383+
*/
1384+
for (const char *q = p; q < end_of_object_name; q++) {
1385+
if (!isxdigit(*q))
1386+
goto out;
1387+
}
1388+
saved = *end_of_object_name;
1389+
*end_of_object_name = '\0';
1390+
have_oid = !repo_get_oid(r, p, &oid);
1391+
*end_of_object_name = saved;
1392+
if (!have_oid)
1393+
goto out; /* object name was a label */
1394+
abbrev = repo_find_unique_abbrev(r, &oid, DEFAULT_ABBREV);
1395+
if (!starts_with(p, abbrev))
1396+
goto out; /* object name was a refname containing only xdigits */
1397+
p += strlen(abbrev);
1398+
strbuf_remove(line, p - line->buf, end_of_object_name - p);
1399+
end_of_object_name = p;
1400+
out:
1401+
*pp = end_of_object_name;
1402+
}
1403+
1404+
static void skip_dash_c(char **pp) {
1405+
char *p = *pp;
1406+
1407+
p += strspn(p, " \t");
1408+
/* The (void) cast is required to silence -Wunused_value */
1409+
(void)(skip_prefix(p, "-C", &p) || skip_prefix(p, "-c", &p));
1410+
*pp = p;
1411+
}
1412+
13681413
/*
13691414
* Turn
13701415
* "pick d6a2f0303e897ec257dd0e0a39a5ccb709bc2047 some message"
13711416
* into
13721417
* "pick d6a2f03 some message"
13731418
*
1374-
* The function assumes that the line does not contain useless spaces
1375-
* before or after the command.
1419+
* Returns false on comment lines, true otherwise
13761420
*/
1377-
static void abbrev_oid_in_line(struct repository *r, struct strbuf *line)
1421+
static bool format_todo_line(struct repository *r, struct strbuf *line)
13781422
{
1379-
struct string_list split = STRING_LIST_INIT_DUP;
1380-
struct object_id oid;
1423+
enum todo_command cmd;
1424+
char *p = line->buf;
13811425

1382-
if (starts_with(line->buf, "exec ") ||
1383-
starts_with(line->buf, "x ") ||
1384-
starts_with(line->buf, "label ") ||
1385-
starts_with(line->buf, "l "))
1386-
return;
1426+
if (!sequencer_parse_todo_command((const char**)&p, &cmd))
1427+
return true; /* keep invalid lines */
1428+
1429+
switch (cmd) {
1430+
case TODO_COMMENT:
1431+
return false;
1432+
1433+
case TODO_MERGE:
1434+
skip_dash_c(&p);
1435+
while (true) {
1436+
p += strspn(p, " \t");
1437+
if (!p[0] || (p[0] == '#' && (!p[1] || isspace(p[1]))))
1438+
break;
1439+
abbrev_oid_in_line(r, line, &p);
1440+
}
1441+
break;
1442+
1443+
case TODO_FIXUP:
1444+
skip_dash_c(&p);
1445+
/* fallthrough */
1446+
case TODO_DROP:
1447+
case TODO_EDIT:
1448+
case TODO_PICK:
1449+
case TODO_RESET:
1450+
case TODO_REVERT:
1451+
case TODO_REWORD:
1452+
case TODO_SQUASH:
1453+
abbrev_oid_in_line(r, line, &p);
1454+
break;
13871455

1388-
if ((2 <= string_list_split(&split, line->buf, " ", 2)) &&
1389-
!repo_get_oid(r, split.items[1].string, &oid)) {
1390-
strbuf_reset(line);
1391-
strbuf_addf(line, "%s ", split.items[0].string);
1392-
strbuf_add_unique_abbrev(line, &oid, DEFAULT_ABBREV);
1393-
for (size_t i = 2; i < split.nr; i++)
1394-
strbuf_addf(line, " %s", split.items[i].string);
1456+
/*
1457+
* Avoid "default" and instead list all the other commands so
1458+
* that -Wswitch warns if a new command is added without handling
1459+
* it in this function.
1460+
*/
1461+
case TODO_BREAK:
1462+
case TODO_EXEC:
1463+
case TODO_LABEL:
1464+
case TODO_NOOP:
1465+
case TODO_UPDATE_REF:
1466+
break;
13951467
}
1396-
string_list_clear(&split, 0);
1468+
1469+
return true;
13971470
}
13981471

13991472
static int read_rebase_todolist(struct repository *r, const char *fname, struct string_list *lines)
@@ -1411,13 +1484,9 @@ static int read_rebase_todolist(struct repository *r, const char *fname, struct
14111484
repo_git_path_replace(r, &buf, "%s", fname));
14121485
}
14131486
while (!strbuf_getline_lf(&buf, f)) {
1414-
if (starts_with(buf.buf, comment_line_str))
1415-
continue;
14161487
strbuf_trim(&buf);
1417-
if (!buf.len)
1418-
continue;
1419-
abbrev_oid_in_line(r, &buf);
1420-
string_list_append(lines, buf.buf);
1488+
if (format_todo_line(r, &buf))
1489+
string_list_append(lines, buf.buf);
14211490
}
14221491
fclose(f);
14231492

0 commit comments

Comments
 (0)