Skip to content

Fix two Windows-only bugs in Git Bash - #224

Open
anarchitect wants to merge 2 commits into
mona-actions:mainfrom
anarchitect:fix/windows-git-bash-compat
Open

anarchitect wants to merge 2 commits into
mona-actions:mainfrom
anarchitect:fix/windows-git-bash-compat

Conversation

@anarchitect

Copy link
Copy Markdown
Contributor

What

Two independent Windows-only bugs in Git Bash. Both are reproducible on a stock Git for Windows install; neither affects Linux or macOS.

The two commits are independent and separately revertable. Happy to split this into two PRs if you would rather take them separately — say the word and I will.


1. isCloud() misdetects Windows, silently corrupting the output

isCloud() matches OSTYPE exactly against msys:

if [[ "$OSTYPE" == "msys" ]]; then

Not every Git for Windows build reports that value. On the ARM64 CLANG build:

$ echo "$OSTYPE"        # Git Bash, Git for Windows 2.x ARM64
cygwin
$ uname -s
MINGW64_NT-10.0-26200-ARM64

The check falls through to the Unix branch, MSYS rewrites the leading slash into a filesystem path, and the call fails:

invalid API endpoint: "C:/Program Files/Git/". Your shell might be rewriting URL paths as filesystem paths.
WARNING: Could not determine GitHub Enterprise Server version

This is not just a warning. With isCloud() failing, github.com is treated as GHES v2.20, which changes what gets written to the CSV:

Correct On affected shells
Column count 28 27
Is_Empty column present dropped from the header
Protected_Branch_Count 0 null on every row

The last one is the reason I would treat this as more than cosmetic: isCompatibleGHESVersion routes the parser to the GHES-only protectedBranches field instead of branchProtectionRules, so branch protection silently reads as null for the whole inventory. A user has no indication the numbers are wrong.

Fixed by matching all the values Windows shells actually report:

case "${OSTYPE}" in
  msys* | cygwin* | win32) ROOT_DATA=$(gh api //) ;;
  *)                       ROOT_DATA=$(gh api /)  ;;
esac

Globs rather than exact matches, since msys and cygwin both appear with version suffixes on some builds.


2. base64: invalid input on every field read

Every run on Windows emits a large volume of:

base64: invalid input

Cause. jq on Windows writes CRLF. Bash splits command substitution on IFS, which contains LF but not CR, so every token from jq -r '.[] | @base64' retains a trailing carriage return:

$ echo -n "$REPOS" | jq -r '.[] | @base64' | od -c | head -4
0000000   e   y   J   u   Y   W   1   l   I   j   o   i   Y   W   d   l
0000020   b   n   R   p   Y   y   1   k   Z   X   Z   v   c   H   M   t
0000040   Y   2   9   k   Z   X   F   s   L   W   R   l   b   W   8   i
0000060   f   Q   =   =  \r  \n
                          ^^^^

GNU coreutils base64 rejects the stray byte, writes to stderr, then decodes the valid prefix anyway — so output is currently correct.

Why I would still fix it rather than leave it:

  • Volume. 19 error lines per repository. A 500-repo organization produces roughly 9,500 lines of stderr, which buries any genuine error and looks to an end user like a broken tool.
  • It depends on unspecified behaviour. Decode-then-warn is a coreutils implementation detail, not a guarantee. A stricter base64 that exits non-zero on invalid input would make _jq return empty and blank every field — turning a loud non-issue into a silent data-loss bug.

Fixed by stripping CR before decoding, at all nine _jq call sites:

echo -n "${REPO_DATA}" | tr -d '\r' | base64 --decode | jq -r "${1}"

tr -d '\r' is a no-op on Linux and macOS, so this is inert on non-Windows platforms.


Verification

Run against a live organization on Git Bash (Git for Windows, ARM64), before and after.

Before:

invalid API endpoint: "C:/Program Files/Git/" ...
WARNING: Could not determine GitHub Enterprise Server version
base64: invalid input          (x57 for 3 repositories)
Columns: 27   Is_Empty: <missing>   Protected_Branch_Count: null

After:

Creating file header...
Getting repositories for org: <org>
Analyzing Repo: ...
The script has completed
Columns: 28   Is_Empty: false   Protected_Branch_Count: 0

No endpoint errors, no base64 output, correct column count and values. bash -n passes.

I have not been able to test on a GHES instance, so a second opinion on the isCloud() change from anyone with GHES access would be welcome — though the change only affects which endpoint string is used on Windows, and leaves the Unix path untouched.

isCloud() only matched OSTYPE 'msys'. Some Git for Windows builds report
'cygwin' instead, including the ARM64 CLANG build. On those the leading
slash in 'gh api /' is rewritten to a filesystem path, the call fails,
and github.com is misidentified as GHES v2.20.

That is not a cosmetic warning. It silently changes the output: the
Is_Empty column is dropped from the header, leaving 35 columns instead
of 36, and Protected_Branch_Count reads the GHES-only protectedBranches
field, so it reports null on every row.

Match msys, cygwin and win32 so the escaped endpoint is used on all
Windows shells.
On Windows, jq emits CRLF line endings. Bash splits command substitution
on IFS, which contains LF but not CR, so every base64 token produced by
'jq -r .[] | @base64' keeps a trailing carriage return.

base64 --decode rejects that byte and prints 'base64: invalid input' to
stderr, then decodes the valid prefix anyway. The output was therefore
correct but accompanied by one error line per field read: 57 lines for a
three repository organization, and proportionally more for a real one.

Strip CR before decoding at all nine call sites.
@anarchitect
anarchitect requested a review from a team as a code owner July 31, 2026 00:04
@amenocal
amenocal requested a review from Copilot July 31, 2026 16:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes two Windows-only Git Bash issues that impact GitHub API endpoint detection and parsing behavior, preventing incorrect GHES/cloud detection and eliminating noisy base64: invalid input stderr output during repository inventory runs.

Changes:

  • Broaden isCloud() Windows detection by matching OSTYPE via case patterns (e.g., msys*, cygwin*, win32) and using the Windows-safe gh api // path form.
  • Strip \r before base64 --decode at the various _jq helper call sites to avoid CRLF-related decode warnings on Windows.
Show a summary per file
File Description
gh-repo-stats Improves Windows/Git Bash compatibility for cloud detection and base64-decoding of jq @base64 outputs.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 1/1 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread gh-repo-stats
Comment on lines 1007 to 1011
REPO_DATA=$1
# Convert the format to JSON
_jq() {
echo -n "${REPO_DATA}" | base64 --decode | jq -r "${1}"
echo -n "${REPO_DATA}" | tr -d '\r' | base64 --decode | jq -r "${1}"
}
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.

3 participants