Merge branch 'sg/rebase-progress'

Use "Erase in Line" CSI sequence that is already used in the editor
support to clear cruft in the progress output.

* sg/rebase-progress:
  progress: use term_clear_line()
  rebase: fix garbled progress display with '-x'
  pager: add a helper function to clear the last line in the terminal
  t3404: make the 'rebase.missingCommitsCheck=ignore' test more focused
  t3404: modernize here doc style
maint
Junio C Hamano 2019-07-09 15:25:45 -07:00
commit 6624e07b36
8 changed files with 105 additions and 99 deletions

View File

@ -1735,6 +1735,7 @@ void setup_pager(void);
int pager_in_use(void); int pager_in_use(void);
extern int pager_use_color; extern int pager_use_color;
int term_columns(void); int term_columns(void);
void term_clear_line(void);
int decimal_width(uintmax_t); int decimal_width(uintmax_t);
int check_pager_config(const char *cmd); int check_pager_config(const char *cmd);
void prepare_pager_args(struct child_process *, const char *pager); void prepare_pager_args(struct child_process *, const char *pager);

View File

@ -96,10 +96,10 @@ static int launch_specified_editor(const char *editor, const char *path,


if (print_waiting_for_editor && !is_terminal_dumb()) if (print_waiting_for_editor && !is_terminal_dumb())
/* /*
* Go back to the beginning and erase the entire line to * Erase the entire line to avoid wasting the
* avoid wasting the vertical space. * vertical space.
*/ */
fputs("\r\033[K", stderr); term_clear_line();
} }


if (!buffer) if (!buffer)

20
pager.c
View File

@ -177,6 +177,26 @@ int term_columns(void)
return term_columns_at_startup; return term_columns_at_startup;
} }


/*
* Clear the entire line, leave cursor in first column.
*/
void term_clear_line(void)
{
if (is_terminal_dumb())
/*
* Fall back to print a terminal width worth of space
* characters (hoping that the terminal is still as wide
* as it was upon the first call to term_columns()).
*/
fprintf(stderr, "\r%*s\r", term_columns(), "");
else
/*
* On non-dumb terminals use an escape sequence to clear
* the whole line, no matter how wide the terminal.
*/
fputs("\r\033[K", stderr);
}

/* /*
* How many columns do we need to show this number in decimal? * How many columns do we need to show this number in decimal?
*/ */

View File

@ -88,7 +88,6 @@ static void display(struct progress *progress, uint64_t n, const char *done)
const char *tp; const char *tp;
struct strbuf *counters_sb = &progress->counters_sb; struct strbuf *counters_sb = &progress->counters_sb;
int show_update = 0; int show_update = 0;
int last_count_len = counters_sb->len;


if (progress->delay && (!progress_update || --progress->delay)) if (progress->delay && (!progress_update || --progress->delay))
return; return;
@ -116,26 +115,21 @@ static void display(struct progress *progress, uint64_t n, const char *done)
if (show_update) { if (show_update) {
if (is_foreground_fd(fileno(stderr)) || done) { if (is_foreground_fd(fileno(stderr)) || done) {
const char *eol = done ? done : "\r"; const char *eol = done ? done : "\r";
size_t clear_len = counters_sb->len < last_count_len ?
last_count_len - counters_sb->len + 1 :
0;
size_t progress_line_len = progress->title_len +
counters_sb->len + 2;
int cols = term_columns();


term_clear_line();
if (progress->split) { if (progress->split) {
fprintf(stderr, " %s%*s", counters_sb->buf, fprintf(stderr, " %s%s", counters_sb->buf,
(int) clear_len, eol); eol);
} else if (!done && cols < progress_line_len) { } else if (!done &&
clear_len = progress->title_len + 1 < cols ? /* The "+ 2" accounts for the ": ". */
cols - progress->title_len - 1 : 0; term_columns() < progress->title_len +
fprintf(stderr, "%s:%*s\n %s%s", counters_sb->len + 2) {
progress->title, (int) clear_len, "", fprintf(stderr, "%s:\n %s%s",
counters_sb->buf, eol); progress->title, counters_sb->buf, eol);
progress->split = 1; progress->split = 1;
} else { } else {
fprintf(stderr, "%s: %s%*s", progress->title, fprintf(stderr, "%s: %s%s", progress->title,
counters_sb->buf, (int) clear_len, eol); counters_sb->buf, eol);
} }
fflush(stderr); fflush(stderr);
} }

View File

@ -3741,8 +3741,11 @@ static int pick_commits(struct repository *r,
unlink(git_path_merge_head(the_repository)); unlink(git_path_merge_head(the_repository));
delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF);


if (item->command == TODO_BREAK) if (item->command == TODO_BREAK) {
if (!opts->verbose)
term_clear_line();
return stopped_at_head(r); return stopped_at_head(r);
}
} }
if (item->command <= TODO_SQUASH) { if (item->command <= TODO_SQUASH) {
if (is_rebase_i(opts)) if (is_rebase_i(opts))
@ -3764,11 +3767,14 @@ static int pick_commits(struct repository *r,
} }
if (item->command == TODO_EDIT) { if (item->command == TODO_EDIT) {
struct commit *commit = item->commit; struct commit *commit = item->commit;
if (!res) if (!res) {
if (!opts->verbose)
term_clear_line();
fprintf(stderr, fprintf(stderr,
_("Stopped at %s... %.*s\n"), _("Stopped at %s... %.*s\n"),
short_commit_name(commit), short_commit_name(commit),
item->arg_len, arg); item->arg_len, arg);
}
return error_with_patch(r, commit, return error_with_patch(r, commit,
arg, item->arg_len, opts, res, !res); arg, item->arg_len, opts, res, !res);
} }
@ -3806,6 +3812,8 @@ static int pick_commits(struct repository *r,
int saved = *end_of_arg; int saved = *end_of_arg;
struct stat st; struct stat st;


if (!opts->verbose)
term_clear_line();
*end_of_arg = '\0'; *end_of_arg = '\0';
res = do_exec(r, arg); res = do_exec(r, arg);
*end_of_arg = saved; *end_of_arg = saved;
@ -3964,10 +3972,13 @@ cleanup_head_ref:
} }
apply_autostash(opts); apply_autostash(opts);


if (!opts->quiet) if (!opts->quiet) {
if (!opts->verbose)
term_clear_line();
fprintf(stderr, fprintf(stderr,
"Successfully rebased and updated %s.\n", "Successfully rebased and updated %s.\n",
head_ref.buf); head_ref.buf);
}


strbuf_release(&buf); strbuf_release(&buf);
strbuf_release(&head_ref); strbuf_release(&head_ref);

View File

@ -75,11 +75,10 @@ test_expect_success 'rebase --keep-empty' '
test_line_count = 6 actual test_line_count = 6 actual
' '


cat > expect <<EOF
error: nothing to do
EOF

test_expect_success 'rebase -i with empty HEAD' ' test_expect_success 'rebase -i with empty HEAD' '
cat >expect <<-\EOF &&
error: nothing to do
EOF
set_fake_editor && set_fake_editor &&
test_must_fail env FAKE_LINES="1 exec_true" git rebase -i HEAD^ >actual 2>&1 && test_must_fail env FAKE_LINES="1 exec_true" git rebase -i HEAD^ >actual 2>&1 &&
test_i18ncmp expect actual test_i18ncmp expect actual
@ -237,25 +236,23 @@ test_expect_success 'exchange two commits' '
test G = $(git cat-file commit HEAD | sed -ne \$p) test G = $(git cat-file commit HEAD | sed -ne \$p)
' '


cat > expect << EOF
diff --git a/file1 b/file1
index f70f10e..fd79235 100644
--- a/file1
+++ b/file1
@@ -1 +1 @@
-A
+G
EOF

cat > expect2 << EOF
<<<<<<< HEAD
D
=======
G
>>>>>>> 5d18e54... G
EOF

test_expect_success 'stop on conflicting pick' ' test_expect_success 'stop on conflicting pick' '
cat >expect <<-\EOF &&
diff --git a/file1 b/file1
index f70f10e..fd79235 100644
--- a/file1
+++ b/file1
@@ -1 +1 @@
-A
+G
EOF
cat >expect2 <<-\EOF &&
<<<<<<< HEAD
D
=======
G
>>>>>>> 5d18e54... G
EOF
git tag new-branch1 && git tag new-branch1 &&
set_fake_editor && set_fake_editor &&
test_must_fail git rebase -i master && test_must_fail git rebase -i master &&
@ -495,15 +492,14 @@ test_expect_success 'commit message retained after conflict' '
git branch -D conflict-squash git branch -D conflict-squash
' '


cat > expect-squash-fixup << EOF
B

D

ONCE
EOF

test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' ' test_expect_success C_LOCALE_OUTPUT 'squash and fixup generate correct log messages' '
cat >expect-squash-fixup <<-\EOF &&
B

D

ONCE
EOF
git checkout -b squash-fixup E && git checkout -b squash-fixup E &&
base=$(git rev-parse HEAD~4) && base=$(git rev-parse HEAD~4) &&
set_fake_editor && set_fake_editor &&
@ -799,13 +795,12 @@ test_expect_success 'rebase -i can copy notes' '
test "a note" = "$(git notes show HEAD)" test "a note" = "$(git notes show HEAD)"
' '


cat >expect <<EOF
an earlier note

a note
EOF

test_expect_success 'rebase -i can copy notes over a fixup' ' test_expect_success 'rebase -i can copy notes over a fixup' '
cat >expect <<-\EOF &&
an earlier note

a note
EOF
git reset --hard n3 && git reset --hard n3 &&
git notes add -m"an earlier note" n2 && git notes add -m"an earlier note" n2 &&
set_fake_editor && set_fake_editor &&
@ -1304,52 +1299,37 @@ test_expect_success 'rebase -i respects rebase.missingCommitsCheck = ignore' '
actual actual
' '


cat >expect <<EOF
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 master)
To avoid this message, use "drop" to explicitly remove a commit.

Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
The possible behaviours are: ignore, warn, error.

Rebasing (1/4)
Rebasing (2/4)
Rebasing (3/4)
Rebasing (4/4)
Successfully rebased and updated refs/heads/missing-commit.
EOF

cr_to_nl () {
tr '\015' '\012'
}

test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' ' test_expect_success 'rebase -i respects rebase.missingCommitsCheck = warn' '
cat >expect <<-EOF &&
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 master)
To avoid this message, use "drop" to explicitly remove a commit.
EOF
test_config rebase.missingCommitsCheck warn && test_config rebase.missingCommitsCheck warn &&
rebase_setup_and_clean missing-commit && rebase_setup_and_clean missing-commit &&
set_fake_editor && set_fake_editor &&
FAKE_LINES="1 2 3 4" \ FAKE_LINES="1 2 3 4" \
git rebase -i --root 2>actual.2 && git rebase -i --root 2>actual.2 &&
cr_to_nl <actual.2 >actual && head -n4 actual.2 >actual &&
test_i18ncmp expect actual && test_i18ncmp expect actual &&
test D = $(git cat-file commit HEAD | sed -ne \$p) test D = $(git cat-file commit HEAD | sed -ne \$p)
' '


cat >expect <<EOF
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 master)
- $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
To avoid this message, use "drop" to explicitly remove a commit.

Use 'git config rebase.missingCommitsCheck' to change the level of warnings.
The possible behaviours are: ignore, warn, error.

You can fix this with 'git rebase --edit-todo' and then run 'git rebase --continue'.
Or you can abort the rebase with 'git rebase --abort'.
EOF

test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' ' test_expect_success 'rebase -i respects rebase.missingCommitsCheck = error' '
cat >expect <<-EOF &&
Warning: some commits may have been dropped accidentally.
Dropped commits (newer to older):
- $(git rev-list --pretty=oneline --abbrev-commit -1 master)
- $(git rev-list --pretty=oneline --abbrev-commit -1 master~2)
To avoid this message, use "drop" to explicitly remove a commit.

Use '\''git config rebase.missingCommitsCheck'\'' to change the level of warnings.
The possible behaviours are: ignore, warn, error.

You can fix this with '\''git rebase --edit-todo'\'' and then run '\''git rebase --continue'\''.
Or you can abort the rebase with '\''git rebase --abort'\''.
EOF
test_config rebase.missingCommitsCheck error && test_config rebase.missingCommitsCheck error &&
rebase_setup_and_clean missing-commit && rebase_setup_and_clean missing-commit &&
set_fake_editor && set_fake_editor &&

View File

@ -49,7 +49,7 @@ create_expected_success_interactive () {
$(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual) $(grep "^Created autostash: [0-9a-f][0-9a-f]*\$" actual)
HEAD is now at $(git rev-parse --short feature-branch) third commit HEAD is now at $(git rev-parse --short feature-branch) third commit
Rebasing (1/2)QRebasing (2/2)QApplied autostash. Rebasing (1/2)QRebasing (2/2)QApplied autostash.
Successfully rebased and updated refs/heads/rebased-feature-branch. Q QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
EOF EOF
} }


@ -73,7 +73,7 @@ create_expected_failure_interactive () {
Rebasing (1/2)QRebasing (2/2)QApplying autostash resulted in conflicts. Rebasing (1/2)QRebasing (2/2)QApplying autostash resulted in conflicts.
Your changes are safe in the stash. Your changes are safe in the stash.
You can run "git stash pop" or "git stash drop" at any time. You can run "git stash pop" or "git stash drop" at any time.
Successfully rebased and updated refs/heads/rebased-feature-branch. Q QSuccessfully rebased and updated refs/heads/rebased-feature-branch.
EOF EOF
} }



View File

@ -213,7 +213,7 @@ test_expect_success TTY 'push shows progress when stderr is a tty' '
cd "$ROOT_PATH"/test_repo_clone && cd "$ROOT_PATH"/test_repo_clone &&
test_commit noisy && test_commit noisy &&
test_terminal git push >output 2>&1 && test_terminal git push >output 2>&1 &&
test_i18ngrep "^Writing objects" output test_i18ngrep "Writing objects" output
' '


test_expect_success TTY 'push --quiet silences status and progress' ' test_expect_success TTY 'push --quiet silences status and progress' '
@ -228,7 +228,7 @@ test_expect_success TTY 'push --no-progress silences progress but not status' '
test_commit no-progress && test_commit no-progress &&
test_terminal git push --no-progress >output 2>&1 && test_terminal git push --no-progress >output 2>&1 &&
test_i18ngrep "^To http" output && test_i18ngrep "^To http" output &&
test_i18ngrep ! "^Writing objects" output test_i18ngrep ! "Writing objects" output
' '


test_expect_success 'push --progress shows progress to non-tty' ' test_expect_success 'push --progress shows progress to non-tty' '
@ -236,7 +236,7 @@ test_expect_success 'push --progress shows progress to non-tty' '
test_commit progress && test_commit progress &&
git push --progress >output 2>&1 && git push --progress >output 2>&1 &&
test_i18ngrep "^To http" output && test_i18ngrep "^To http" output &&
test_i18ngrep "^Writing objects" output test_i18ngrep "Writing objects" output
' '


test_expect_success 'http push gives sane defaults to reflog' ' test_expect_success 'http push gives sane defaults to reflog' '