Skip to content

Add opt-in stream_hook_output to show git hook output live (e.g. post-checkout migrations)#1962

Open
jcarlos7121 wants to merge 4 commits into
NeogitOrg:masterfrom
jcarlos7121:feature/stream-hook-output
Open

Add opt-in stream_hook_output to show git hook output live (e.g. post-checkout migrations)#1962
jcarlos7121 wants to merge 4 commits into
NeogitOrg:masterfrom
jcarlos7121:feature/stream-hook-output

Conversation

@jcarlos7121
Copy link
Copy Markdown

@jcarlos7121 jcarlos7121 commented May 27, 2026

What's this?

A small, opt-in config flag — stream_hook_output (default false) — that lets you actually watch a git hook's output stream into the Neogit console while it runs.

My setup runs a post-checkout hook (the hookup Ruby gem) that runs DB migrations whenever I switch branches. Today that hook fires on every checkout but basically gets lost currently. The output is captured, but it gets swallowed silently.

Why it doesn't already work

Turns out checkout is the only hook-bearing op that runs blocking (branch.checkout.call { await = true }). A blocking jobwait freezes redraws, and the vim.schedule'd "show console" timer can't fire mid-run — by the time it could, the result is already set and it bails, then auto-close finishes it off on success. So the console never gets a chance to stream. Meanwhile merge/push run async and already stream their hook output via the existing 800ms timer — checkout was just the odd one out.

What the flag does

When stream_hook_output = true:

  • branch.checkout/track run async instead of blocking — but only when a post-checkout hook actually exists — so the existing console machinery can stream the output live as it's produced.
  • A tiny tweak in process.lua's timer force-shows the console for hook processes, so it works even if you've turned auto_show_console off.
  • Close-on-success / stay-open-on-failure are unchanged — those already do exactly the right thing (auto_close_console + the existing hook-failure branch). So you watch it run, it tidies up after itself on success, and it sticks around so you can read the error if the hook fails.

Default is false, so this is zero behavior change unless you opt in.

Scope / notes

  • Applies to the non-suppressed hook ops (checkout, merge, push). rebase/bisect run with long = true (console suppressed), so they're intentionally out of scope.
  • Switching checkout to async is safe: popup actions already run inside an a.void coroutine, so the async path yields and resumes with the ProcessResult exactly like before, and the runner falls back to blocking if it's ever called outside a coroutine.

Tests

  • New branch_checkout_await_spec.lua asserting checkout takes the async path only when the flag + a post-checkout hook are present (and blocks otherwise).
  • New config-validation case in config_spec.lua.
  • Full suite green, stylua clean. Documented in README + doc/neogit.txt.

jcarlos7121 and others added 4 commits May 27, 2026 11:55
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…hook exists

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant