Zsh: set aside a command with “Escape Q” / push-line

Artist’s impression of a shell command swimming away, to return later.

Do you ever do this? You carefully type out a command, like this pytest one:

$ pytest tests/test_checkout.py -k discount --reuse-db -x

…then, just before pressing Enter, you remember that something will stop it from succeeding, like being on the wrong Git branch.

What now?

Maybe you run the command anyway, to put it in your history, letting it fail or cancelling it with Ctrl-C. Then you can run your setup command.

Or maybe you press Ctrl-A to jump to the start, and add the setup command first, like git switch fix-discounts &&, and press Enter. Then both commands will run together, but they’re in one combined history entry.

Both of these options work, but they’re fiddly.

Zsh has a neater feature to help here: the push-line widget. Press Escape, release it, then press q. Zsh stores your current command away and clears the prompt, ready for a different command:

$ pytest tests/test_checkout.py -k discount --reuse-db -x<Escape q>

$

Now you can run whatever you need, such as switching branch:

$ git switch fix-discounts
Switched to branch 'fix-discounts'

When that command finishes, Zsh restores the stored command at the next prompt, with the cursor at the end, ready to run:

$ pytest tests/test_checkout.py -k discount --reuse-db -x

Press Enter, and your tests run on the right branch.

push-line works for any “oops, I forgot to do a thing first” moment, like:

Use push-line-or-edit instead

I recommend rebinding Esc q to a variant widget, push-line-or-edit, in your ~/.zshrc:

# Make Escape Q push the current line, or the whole edit if it’s multi-line.
# Per: https://adamj.eu/tech/2026/10/06/zsh-push-line/
bindkey '^[q' push-line-or-edit

At a normal prompt, push-line-or-edit behaves exactly like push-line. The difference comes with multi-line commands (“edits”), such as a long pytest command split with backslash line continuations:

$ pytest tests/test_checkout.py \
∙  -k discount \
∙  --reuse-db \
∙  -x

Here, the default push-line widget only stores the current line, -x, which is not much use. push-line-or-edit instead pulls the whole command back into a single editable buffer:

$ pytest tests/test_checkout.py \
  -k discount \
  --reuse-db \
  -x

Press Escape, q again, and the whole command is set aside, ready to return after your next command. So push-line-or-edit kinda just does the right thing, with no real downside. I am not sure why it’s not the default.

Oh My Zsh

If you use Oh My Zsh, like me, you get a few extras around push-line:

But Oh My Zsh doesn’t bind push-line-or-edit, so you’ll still want to add the rebinding above. To cover all three shortcuts:

# Make Escape q, Escape q, and Control-Q push the current line, or the whole
# edit if it’s multi-line.
# Per: https://adamj.eu/tech/2026/10/06/zsh-push-line/
bindkey '^[q' push-line-or-edit
bindkey '^[Q' push-line-or-edit
bindkey '^Q' push-line-or-edit

Fin

Q up those commands for later,

—Adam


Check out my new book Boost Your GitHub DX.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: