Commit bd51e38
authored
fix(git): surface the real cause of git failures instead of a static message (#42053)
Fixes APP-15731
Slack thread that prompted this:
https://theappsmith.slack.com/archives/C09GSB3APNU/p1784892702257989
## Why
A customer's push to a self-hosted GitLab was rejected. The ticket ran
for three days with support checking branch protection, push rules and
deploy-key permissions in turn, because Appsmith never showed the
reason. It could not: the reason was thrown away before it was ever
logged.
JGit reports a rejected push in two separate places.
`RemoteRefUpdate.getMessage()` carries the terse report-status reason,
which for every server-side hook is the same literal `pre-receive hook
declined`. The explanation an operator actually needs — "GitLab: You are
not allowed to push code to protected branches on this project", a
push-rule violation, a secret-scanning block — travels on the sideband
channel and is reachable only through `PushResult.getMessages()`. We
read the first and dropped the second, then replaced the failure with a
hardcoded guess: *"make sure you don't have any rules enabled on the
branch X"*. No log level recovered it.
That same shape — swallow the real error, emit a static string — recurs
across the git flows. This PR fixes the class, not just the instance.
## What changed
**The remote's own words now reach both the logs and the user.**
`FSGitHandlerCEImpl.summarisePushResult` captures the sideband response,
logs it once with repo, ref and remote, and carries it to
`GitFSServiceCEImpl`, which puts it in the error the user sees instead
of the guess. When the remote sends nothing back, the message names what
to check rather than asserting a cause.
**Stack traces survive.** Around 20 sites used `log.error("...",
e.getMessage())`. SLF4J only captures a stack trace when the `Throwable`
is the final argument, so these produced one line and nothing else.
**Silent recovery is now visible.** `resetHard` logged a message and
returned `false`, and the caller ignored it. After a rejected push
nobody could tell whether the local rollback worked, so a commit could
exist locally and nowhere else with no trace.
**Lock lifecycle is diagnosable.** Contention, retry exhaustion and
release logged nothing. "Another git operation is in progress" had no
diagnostics at all. Per-attempt contention is at `debug` so a blocked
operation does not emit 20 warnings; a single warning is raised when the
retries run out.
**Auto-commit stops failing invisibly.** It runs in the background, so
eligibility errors logged at `debug` and rejected pushes logged not at
all were effectively undetectable. `GitAutoCommitHelperImpl` also logged
"is not allowed" unconditionally *before* the eligibility check, so
every successful auto-commit logged the opposite of what happened.
**Correlation ids** (artifact, ref, repo, workspace) added to existing
git error logs.
## Behaviour changes
Three genuine bugs surfaced during the audit and are fixed here:
- The rejection check tested for `REJECTED_OTHERREASON`; JGit's enum is
`REJECTED_OTHER_REASON`. The branch was dead, so any rejection whose
message was not literally "pre-receive hook declined" fell through and
**was reported to the user as a successful push** while the commit never
left the server.
- Two `Mono.error(error)` results in the merge flows were constructed
but never returned, so an `AppsmithException` was replaced by a generic
one.
- The checkout guard compared a `GitRefDTO` to a `String` and so never
matched, leaking JGit's raw `Ref <name> already exists` to the user
instead of Appsmith's message.
The user-facing text for a rejected push changes deliberately, from the
hardcoded branch-rules guess to the remote's actual response.
## Not in this PR
Deliberately kept out to stay reviewable: `ObservabilityLogger` emits
the stack twice (SLF4J plus `printStackTrace`), and
`GlobalExceptionHandler.getResponseDTOMono` releases the lock using a
bare application id while `GitRedisUtils` stores it under
`application-<id>`, so that defensive release never matches. Both are
filed separately.
## Relationship to the EE PR
EE counterpart: appsmithorg/appsmith-ee#9373
This PR carries the 15 files shared between CE and EE. The EE PR
additionally covers EE-only surfaces with no CE equivalent: package git,
the SSH key service, the continuous-delivery publish path, and EE's
`FileUtilsImpl`.
## Test plan
- [ ] `mvn -pl appsmith-server -am compile` passes (verified locally,
BUILD SUCCESS)
- [ ] Spotless clean (verified locally)
- [ ] Reject a push on a deploy preview with a protected branch on the
remote, and confirm the remote's message appears in the server log and
in the UI error
- [ ] Confirm a successful commit and push emits no new INFO lines
- [ ] Hold a git lock and confirm one warning on retry exhaustion, not
twenty
- [ ] Confirm auto-commit no longer logs "is not allowed" for an
eligible run
## Automation
/ok-to-test tags="@tag.All"
<!-- This is an auto-generated comment: Cypress test results -->
> [!TIP]
> 🟢 🟢 🟢 All cypress tests have passed! 🎉 🎉 🎉
> Workflow run:
<https://github.com/appsmithorg/appsmith/actions/runs/30426486864>
> Commit: 67dc29f
> <a
href="https://internal.appsmith.com/app/cypress-dashboard/rundetails-65890b3c81d7400d08fa9ee5?branch=master&workflowId=30426486864&attempt=2"
target="_blank">Cypress dashboard</a>.
> Tags: `@tag.All`
> Spec:
> <hr>Wed, 29 Jul 2026 14:28:10 UTC
<!-- end of auto-generated comment: Cypress test results -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Improved Git push status reporting with centralized accepted/rejected
handling and clearer remote rejection diagnostics.
* Fixed remote reference matching during checkout to avoid incorrect
“already exists” results.
* Enhanced push rejection recovery messaging for non-fast-forward and
other remote rejection cases.
* **Reliability**
* Strengthened contextual error logging across git file/repo operations,
including richer path and exception details.
* Improved Redis lock acquisition/release and auto-commit
eligibility/cleanup diagnostics, including outcomes when lock cleanup is
skipped or fails.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->1 parent 8ac6dc9 commit bd51e38
15 files changed
Lines changed: 454 additions & 133 deletions
File tree
- app/server
- appsmith-git/src/main/java/com/appsmith/git
- constants/ce
- files
- operations
- handler/ce
- appsmith-server/src/main/java/com/appsmith/server
- applications/git
- aspect/ce
- git
- autocommit
- helpers
- central
- fs
- helpers
- ce
Lines changed: 9 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
35 | 35 | | |
36 | 36 | | |
37 | 37 | | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
38 | 47 | | |
Lines changed: 22 additions & 14 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
142 | 147 | | |
143 | 148 | | |
144 | 149 | | |
| |||
197 | 202 | | |
198 | 203 | | |
199 | 204 | | |
200 | | - | |
201 | | - | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
202 | 210 | | |
203 | 211 | | |
204 | 212 | | |
| |||
235 | 243 | | |
236 | 244 | | |
237 | 245 | | |
238 | | - | |
239 | | - | |
| 246 | + | |
240 | 247 | | |
241 | 248 | | |
242 | 249 | | |
| |||
250 | 257 | | |
251 | 258 | | |
252 | 259 | | |
253 | | - | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
254 | 265 | | |
255 | 266 | | |
256 | 267 | | |
257 | | - | |
| 268 | + | |
258 | 269 | | |
259 | 270 | | |
260 | 271 | | |
| |||
296 | 307 | | |
297 | 308 | | |
298 | 309 | | |
299 | | - | |
300 | | - | |
| 310 | + | |
301 | 311 | | |
302 | 312 | | |
303 | 313 | | |
| |||
435 | 445 | | |
436 | 446 | | |
437 | 447 | | |
438 | | - | |
439 | | - | |
| 448 | + | |
440 | 449 | | |
441 | 450 | | |
442 | 451 | | |
| |||
454 | 463 | | |
455 | 464 | | |
456 | 465 | | |
457 | | - | |
458 | | - | |
| 466 | + | |
459 | 467 | | |
460 | 468 | | |
461 | 469 | | |
| |||
490 | 498 | | |
491 | 499 | | |
492 | 500 | | |
493 | | - | |
| 501 | + | |
494 | 502 | | |
495 | 503 | | |
496 | 504 | | |
| |||
529 | 537 | | |
530 | 538 | | |
531 | 539 | | |
532 | | - | |
| 540 | + | |
533 | 541 | | |
534 | 542 | | |
535 | 543 | | |
| |||
Lines changed: 22 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
80 | 80 | | |
81 | 81 | | |
82 | 82 | | |
83 | | - | |
| 83 | + | |
84 | 84 | | |
85 | 85 | | |
86 | 86 | | |
| |||
141 | 141 | | |
142 | 142 | | |
143 | 143 | | |
144 | | - | |
| 144 | + | |
145 | 145 | | |
146 | 146 | | |
147 | 147 | | |
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
167 | | - | |
168 | | - | |
169 | | - | |
170 | | - | |
171 | | - | |
| 167 | + | |
172 | 168 | | |
173 | 169 | | |
174 | 170 | | |
| |||
192 | 188 | | |
193 | 189 | | |
194 | 190 | | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
212 | | - | |
213 | | - | |
| 212 | + | |
214 | 213 | | |
215 | 214 | | |
216 | 215 | | |
| |||
233 | 232 | | |
234 | 233 | | |
235 | 234 | | |
236 | | - | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
237 | 239 | | |
238 | 240 | | |
239 | 241 | | |
| |||
256 | 258 | | |
257 | 259 | | |
258 | 260 | | |
259 | | - | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
260 | 265 | | |
261 | 266 | | |
262 | 267 | | |
| |||
272 | 277 | | |
273 | 278 | | |
274 | 279 | | |
275 | | - | |
| 280 | + | |
276 | 281 | | |
277 | 282 | | |
278 | 283 | | |
| |||
287 | 292 | | |
288 | 293 | | |
289 | 294 | | |
290 | | - | |
| 295 | + | |
291 | 296 | | |
292 | | - | |
| 297 | + | |
293 | 298 | | |
294 | 299 | | |
295 | 300 | | |
| |||
307 | 312 | | |
308 | 313 | | |
309 | 314 | | |
310 | | - | |
| 315 | + | |
311 | 316 | | |
312 | 317 | | |
313 | 318 | | |
| |||
332 | 337 | | |
333 | 338 | | |
334 | 339 | | |
335 | | - | |
| 340 | + | |
| 341 | + | |
336 | 342 | | |
337 | 343 | | |
338 | 344 | | |
| |||
0 commit comments