fix: make aidevops update resilient — recover from stuck versions (#2288)#2289
fix: make aidevops update resilient — recover from stuck versions (#2288)#2289marcusquinn merged 1 commit intomainfrom
Conversation
… detached HEAD Fixes #2288 — aidevops update stuck on old version (e.g. 2.125 while 2.128.3 available). Root cause: git pull --ff-only fails when the working tree is dirty or local history has diverged, with no recovery path. Users on pre-PR#2287 versions could not get the dirty-tree fix because the fix itself required a successful pull. Three changes: 1. Ensure local repo is on main branch before pulling (handles detached HEAD) 2. Clean both staged and unstaged changes before pull (extends PR #2287 fix) 3. Fall back to git reset --hard origin/main when --ff-only fails, instead of returning an error — the install repo should always mirror origin/main exactly
|
Warning Rate limit exceeded
⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary of ChangesHello @marcusquinn, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly improves the resilience of the 'aidevops update' command by addressing common scenarios that could cause it to get stuck. It ensures that the update process can reliably recover from issues like dirty working trees, detached HEADs, or diverged local history, allowing users to consistently update to the latest version. The changes implement a more robust Git update mechanism, including proactive branch management, comprehensive cleanup of local changes, and a hard reset fallback, to maintain a clean and up-to-date local repository. Highlights
Changelog
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
🔍 Code Quality Report�[0;35m[MONITOR]�[0m Code Review Monitoring Report �[0;34m[INFO]�[0m Latest Quality Status: �[0;34m[INFO]�[0m Recent monitoring activity: 📈 Current Quality Metrics
Generated on: Wed Feb 25 15:41:54 UTC 2026 Generated by AI DevOps Framework Code Review Monitoring |
|
There was a problem hiding this comment.
Code Review
This pull request significantly improves the resilience of the aidevops update command by handling cases where git pull --ff-only would previously fail, such as a dirty working tree or diverged history. The introduction of a branch guard, cleanup for staged files, and a git reset --hard fallback are excellent enhancements. My review focuses on a recurring pattern of suppressing stderr on git commands, which can hide important debugging information. All suggested changes align with the repository's rules, advocating for the removal of 2>/dev/null in favor of more targeted suppression (like --quiet) or allowing stderr to be visible, especially when || true or similar constructs are used to handle command failures gracefully.
| current_branch=$(git branch --show-current 2>/dev/null || echo "") | ||
| if [[ "$current_branch" != "main" ]]; then | ||
| print_info "Switching to main branch..." | ||
| git checkout main --quiet 2>/dev/null || git checkout -b main origin/main --quiet 2>/dev/null || true |
There was a problem hiding this comment.
Suppressing stderr with 2>/dev/null can hide important error messages if this command fails for reasons other than the branch not existing (e.g., repository corruption, permissions issues). The --quiet flag already handles standard output. It's better to let stderr be visible for debugging, especially since the || chain is designed to handle failures.
| git checkout main --quiet 2>/dev/null || git checkout -b main origin/main --quiet 2>/dev/null || true | |
| git checkout main --quiet || git checkout -b main origin/main --quiet || true |
References
- When using git commands (like 'init', 'remote') in shell scripts, use the '-q' flag to suppress standard output instead of '2>/dev/null', ensuring that error messages on stderr remain visible for debugging.
| # Handles both staged and unstaged changes. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2286 | ||
| if ! git diff --quiet 2>/dev/null; then | ||
| if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then |
There was a problem hiding this comment.
The git diff --quiet command should not produce output on stderr during normal operation. Suppressing stderr with 2>/dev/null is likely redundant and could mask underlying system errors or problems with the git installation. It's safer to remove the redirection to ensure all potential errors are visible for debugging.
| if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then | |
| if ! git diff --quiet || ! git diff --cached --quiet; then |
References
- Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.
| if ! git diff --quiet 2>/dev/null; then | ||
| if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then | ||
| print_info "Cleaning up stale working tree changes..." | ||
| git reset HEAD -- . 2>/dev/null || true |
There was a problem hiding this comment.
Suppressing stderr with 2>/dev/null can hide important error messages if git reset fails for unexpected reasons (e.g., file permissions, repository corruption). Since you're using || true to prevent script exit, it's better to allow error messages to be printed for easier debugging.
| git reset HEAD -- . 2>/dev/null || true | |
| git reset HEAD -- . || true |
References
- Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.
| if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then | ||
| print_info "Cleaning up stale working tree changes..." | ||
| git reset HEAD -- . 2>/dev/null || true | ||
| git checkout -- . 2>/dev/null || true |
There was a problem hiding this comment.
Suppressing stderr with 2>/dev/null can hide important error messages if git checkout fails for unexpected reasons (e.g., file permissions, repository corruption). Since you're using || true to prevent script exit, it's better to allow error messages to be printed for easier debugging.
| git checkout -- . 2>/dev/null || true | |
| git checkout -- . || true |
References
- Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.
| # by aidevops and should always track origin/main exactly. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2288 | ||
| print_warning "Fast-forward pull failed — resetting to origin/main..." | ||
| git reset --hard origin/main --quiet 2>/dev/null || { |
There was a problem hiding this comment.
This git reset --hard is a critical recovery step. Suppressing stderr with 2>/dev/null hides the reason for failure if the reset doesn't work, making it difficult to diagnose the problem. The error handling block will be more informative if the original error from git is visible.
| git reset --hard origin/main --quiet 2>/dev/null || { | |
| git reset --hard origin/main --quiet || { |
References
- Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.
| # Print bounded summary of meaningful changes | ||
| if [[ "$old_hash" != "$new_hash" ]]; then | ||
| local total_commits | ||
| total_commits=$(git rev-list --count "$old_hash..$new_hash" 2>/dev/null || echo "0") |
There was a problem hiding this comment.
While the || echo "0" correctly prevents the script from exiting if git rev-list fails, suppressing stderr with 2>/dev/null hides the actual error message. This makes it harder to debug issues that aren't just an invalid commit range (e.g., a problem with git itself). It's better to let the error be visible.
| total_commits=$(git rev-list --count "$old_hash..$new_hash" 2>/dev/null || echo "0") | |
| total_commits=$(git rev-list --count "$old_hash..$new_hash" || echo "0") |
References
- In shell scripts with 'set -e' enabled, use '|| true' to prevent the script from exiting when a command like 'jq' fails on an optional lookup. Do not suppress stderr with '2>/dev/null' so that actual syntax or system errors remain visible for debugging.
| # Safety net: discard any working tree changes setup.sh may have introduced | ||
| # (e.g. chmod on tracked scripts, scan results written to repo) | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2286 | ||
| git checkout -- . 2>/dev/null || true |
There was a problem hiding this comment.
Suppressing stderr with 2>/dev/null on this final cleanup step can hide errors related to file permissions or other issues that might prevent git checkout from succeeding. Since || true is used to prevent script exit, allowing errors to be displayed would be more informative for debugging.
| git checkout -- . 2>/dev/null || true | |
| git checkout -- . || true |
References
- Avoid using '2>/dev/null' for blanket suppression of command errors in shell scripts to ensure that authentication, syntax, or system issues remain visible for debugging.
🤖 Augment PR SummarySummary: Improves 🤖 Was this summary useful? React with 👍 or 👎 |
| current_branch=$(git branch --show-current 2>/dev/null || echo "") | ||
| if [[ "$current_branch" != "main" ]]; then | ||
| print_info "Switching to main branch..." | ||
| git checkout main --quiet 2>/dev/null || git checkout -b main origin/main --quiet 2>/dev/null || true |
There was a problem hiding this comment.
git checkout ... || ... || true masks branch-switch failures, so cmd_update() may continue in a detached/incorrect branch state without any signal. Consider verifying that the checkout actually succeeded (or at least warning) so updates don’t silently rely on the later reset path.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| # Handles both staged and unstaged changes. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2286 | ||
| if ! git diff --quiet 2>/dev/null; then | ||
| if ! git diff --quiet 2>/dev/null || ! git diff --cached --quiet 2>/dev/null; then |
There was a problem hiding this comment.
This cleanup detects staged/unstaged diffs, but it won’t catch untracked files that can still block git pull/git reset (e.g., “untracked working tree file would be overwritten”). If the goal is to fully “unstick” updates, it may be worth accounting for that class of failure too.
Severity: medium
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.
| # by aidevops and should always track origin/main exactly. | ||
| # See: https://github.com/marcusquinn/aidevops/issues/2288 | ||
| print_warning "Fast-forward pull failed — resetting to origin/main..." | ||
| git reset --hard origin/main --quiet 2>/dev/null || { |
There was a problem hiding this comment.
Because git reset --hard origin/main redirects stderr to /dev/null, the user won’t see the underlying reason when it fails (often the key clue for remediation). Surfacing the git error output in the failure path would make troubleshooting much easier.
Severity: low
🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.



Summary
Fixes #2288 —
aidevops updatestuck on old version (e.g. 2.125 while 2.128.3 is available).Root Cause
cmd_update()usesgit pull --ff-only origin mainwhich fails permanently when:set_permissions()andupdate_scan_results_log()modified tracked files in the git repo, dirtying the working tree.--ff-onlyrefuses to pull over dirty files.--ff-onlyfails with no recovery path.The old code returned an error on
--ff-onlyfailure, leaving the user permanently stuck.Fix (3 parts)
mainbefore pulling (handles detached HEAD from tag checkouts or interrupted operations)git diff --cached) not just unstaged--ff-onlyfails, fall back togit reset --hard origin/maininstead of returning an error — the install repo at~/Git/aidevopsshould always mirrororigin/mainexactly (matchessetup.shbootstrap behavior at line 401-405)Also adds
--tagstogit fetchfor version tag consistency.Testing
test-smoke-help.shbash -nEdge Cases Handled
--ff-onlyfails, stuck--ff-onlyfails, stuck--ff-onlyfails, error returnedreset --hard origin/maingit pullfails (no branch)mainfirstgit rev-listfails after resetset -eecho "0"