git-remote-entire: relay helper-status before send-pack exit check · Entire

git-remote-entire: relay helper-status before send-pack exit check

ad52a59→main·

pjbgf·1mo ago·1 file·+17 added/-10 removed

send-pack exits non-zero on per-ref rejections (D/F conflict, protected branch, server hook decline). The buffered `error refs/X ` lines are what git's transport-helper.c reads to render the user-visible `! [remote rejected]` output. Forwarding helper-status only on the happy path meant Wait/feed errors swallowed those lines, leaving users with only `send-pack exited with error: exit status 1`.

Relay helper-status before checking exit codes so the real reason reaches the user. Examples now surfaced:

Branch protection violation

! [remote rejected] branch-test -> branch-test (upstream: push declined due to repository rule violations) error: failed to push some refs to 'X'

Invalid ref:

! [remote rejected] test-prefix -> test-prefix (ref name conflicts with an existing ref namespace) error: failed to push some refs to 'X'

Permissions:

! [remote rejected] new-test/repo -> new-test/repo (pushing to GitHub: tracing transport: handshake: http transport: authorization failed: unexpected requesting "https://github.com/x/x/info/refs?service=git-receive-pack" status code: 403: Permission to x/x.git denied to .) error: failed to push some refs to 'X'

Assisted-by: Claude Opus 4.7 noreply@anthropic.com Signed-off-by: Paulo Gomes paulo@entire.io

Sessions

25d3ab26f571View transcript

Fix Git Remote Helper Status Relay

Claude Code·Opus 4.7·1 step

Changes

1

150 unmodified lines

151
152
153
154
155
156
157
158
159
160
161
162
163
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179

150 unmodified lines

\t\treturn fmt.Errorf("reading helper-status: %w", err)
\t}\n
\tif err := <-feedErr; err != nil {\n\t\tif waitErr := sp.Wait(); waitErr != nil {\n\t\t\treturn errors.Join(err, fmt.Errorf("send-pack exited after feeder error: %w", waitErr))\n\t\t}\n\t\treturn err\n\t}\n\tif err := sp.Wait(); err != nil {\n\t\treturn fmt.Errorf("send-pack exited with error: %w", err)\n\t}\n
\n\t// Relay helper-status before checking exit codes. send-pack exits\n\t// non-zero on per-ref rejections (D/F conflict, protected branch,\n\t// hook decline); the buffered `error refs/X <reason>` lines are\n\t// what git's transport-helper.c reads to print `! [remote rejected]\n\t// refs/X (<reason>)`. Returning early on Wait/feed errors swallowed\n\t// them, leaving users with only `send-pack exited with error: exit\n\t// status 1`.
\tif _, err := stdout.Write(helperStatus); err != nil {\n\t\treturn fmt.Errorf("writing helper-status: %w", err)\n\t}\n\tif _, err := fmt.Fprintln(stdout); err != nil {\n\t\treturn fmt.Errorf("writing push terminator: %w", err)\n\t}\n
\tif err := <-feedErr; err != nil {\n\t\tif waitErr := sp.Wait(); waitErr != nil {\n\t\t\treturn errors.Join(err, fmt.Errorf("send-pack exited after feeder error: %w", waitErr))\n\t\t}\n\t\treturn err\n\t}\n\tif err := sp.Wait(); err != nil {\n\t\treturn fmt.Errorf("send-pack exited with error: %w", err)\n\t}\n\treturn nil\n}\n```

Minternal/remotehelper/githelper/push.go+17/-10