18

git add --patch is an integral part of my Git workflow. The only thing which irritates me about it is constantly having to press the Enter key after each y or n. Is there any way to make Git accept the answer to a question with just a single y or n keystroke?

Alex D
  • 29,755
  • 7
  • 80
  • 126

2 Answers2

30

That would be the Git configuration option interactive.singleKey.

interactive.singleKey

In interactive commands, allow the user to provide one-letter input with a single key (i.e., without hitting enter). Currently this is used by the --patch mode of git-add(1), git-checkout(1), git-commit(1), git-reset(1), and git-stash(1). Note
that this setting is silently ignored if portable keystroke input is not available; requires the Perl module Term::ReadKey.

That is, in your .gitconfig or equivalent file, add:

[interactive]
    singleKey = true

Or run git config [--global] interactive.singleKey yes, if you like yes better than true and commands better than editors.

Ry-
  • 218,210
  • 55
  • 464
  • 476
1

I had to run sudo cpan Term::ReadKey to get the required Perl module

Not with the next Git 2.26 (Q1 2020), since git-add--interactive.perl is being ported in C, and that involves interactive.singlekey .

See commit b2627cc, commit 12acdf5, commit e118f06, commit 04f816b, commit a5e46e6, commit 9ea416c, commit 94ac3c3, commit 08b1ea4, commit 180f48d, commit 1e4ffc7 (14 Jan 2020) by Johannes Schindelin (dscho).
(Merged by Junio C Hamano -- gitster -- in commit 76c57fe, 05 Feb 2020)

built-in add -p: handle Escape sequences more efficiently

Signed-off-by: Johannes Schindelin

When interactive.singlekey = true, we react immediately to keystrokes, even to Escape sequences (e.g. when pressing a cursor key).

The problem with Escape sequences is that we do not really know when they are done, and as a heuristic we poll standard input for half a second to make sure that we got all of it.

While waiting half a second is not asking for a whole lot, it can become quite annoying over time, therefore with this patch, we read the terminal capabilities (if available) and extract known Escape sequences from there, then stop polling immediately when we detected that the user pressed a key that generated such a known sequence.

This recapitulates the remaining part of b5cc003253c8 ("add -i: ignore terminal escape sequences", 2011-05-17, Git v1.7.6-rc0 -- merge).

Note: We do not query the terminal capabilities directly. That would either require a lot of platform-specific code, or it would require linking to a library such as ncurses.

Linking to a library in the built-ins is something we try very hard to avoid (we even kicked the libcurl dependency to a non-built-in remote helper, just to shave off a tiny fraction of a second from Git's startup time). And the platform-specific code would be a maintenance nightmare.

Even worse: in Git for Windows' case, we would need to query MSYS2 pseudo terminals, which git.exe simply cannot do (because it is intentionally not an MSYS2 program).

To address this, we simply spawn infocmp -L -1 and parse its output (which works even in Git for Windows, because that helper is included in the end-user facing installations).

This is done only once, as in the Perl version, but it is done only when the first Escape sequence is encountered, not upon startup of git add -i; This saves on startup time, yet makes reacting to the first Escape sequence slightly more sluggish.
But it allows us to keep the terminal-related code encapsulated in the compat/terminal.c file.


With Git 2.36 (Q2 2022), the single-key interactive operation used by "git add -p"(man) has been made more robust.

See commit ac618c4, commit 2c68602, commit f7da756, commit 24d7ce3 (22 Feb 2022) by Phillip Wood (phillipwood).
(Merged by Junio C Hamano -- gitster -- in commit 214919b, 21 Mar 2022)

add -p: disable stdin buffering when interactive.singlekey is set

Signed-off-by: Phillip Wood

The builtin "add -p" reads the key "F2" as three separate keys "^[", "O" and "Q".
The "Q" causes it to quit which is probably not what the user was expecting.

This is because it uses poll() to check for pending input when reading escape sequences but reads the input with getchar() which is buffered by default and so hoovers up all the pending input leading poll() think there isn't anything pending.

Fix this by calling setbuf() to disable input buffering if interactive.singlekey is set.

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250