Skip to content

Improve libgit2 build reliability - #97

Merged
hannesa2 merged 5 commits into
gitx:masterfrom
hbmartin:codex/libgit2-build-reliability
Sep 22, 2026
Merged

hannesa2 merged 5 commits into
gitx:masterfrom
hbmartin:codex/libgit2-build-reliability

Conversation

@hbmartin

Copy link
Copy Markdown

Summary

  • declare the libgit2 build script inputs and archive output so Xcode can skip unchanged rebuilds
  • skip the expensive libgit2 rebuild when no source file is newer than the archive
  • use POSIX-compatible shell syntax and restrict the current build configurations to the supported architecture

Why

GitX rebuilds libgit2 on every application and test invocation, substantially increasing local and CI turnaround time. The build phase did not declare its dependencies, and its script had no freshness check.

Validation

  • sh -n script/update_libgit2
  • GitX Debug application build
  • GitX unit and repository-integration suite: 34 passed, 0 failed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved cache invalidation, dependency tracking, error handling, and architecture issues block approval.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Improves libgit2 build reliability through incremental rebuilds and Xcode dependency tracking.

Changes:

  • Adds archive freshness checks and POSIX shell syntax.
  • Declares Xcode script inputs and output.
  • Restricts supported build architectures.
File summaries
File Review summary
script/update_libgit2 Adds caching, but revision/deletion changes, architecture differences, build recipe changes, and masked find failures can leave stale or incompatible archives.
ObjectiveGitFramework.xcodeproj/project.pbxproj Adds dependency declarations, but the source set is incomplete and excluding x86_64 conflicts with the Intel CI job.
Review details

Suppressed comments (4)

ObjectiveGitFramework.xcodeproj/project.pbxproj:1790

  • The Release project configuration is used by the archive job, but excluding x86_64 here leaves no valid architecture on the workflow's macos-15-intel job (.github/workflows/BuildPR.yml:17-22). The Mac archive therefore fails on Intel. Either keep x86_64 enabled or update/remove that CI job as part of this change.
				EXCLUDED_ARCHS = x86_64;

ObjectiveGitFramework.xcodeproj/project.pbxproj:1926

  • This project-level Test setting excludes x86_64, so the repository's Intel test/build configuration cannot produce a valid architecture. This conflicts with the Intel job still declared in .github/workflows/BuildPR.yml:17-22; retain that architecture or update the job and supported-architecture contract together.
				EXCLUDED_ARCHS = x86_64;

ObjectiveGitFramework.xcodeproj/project.pbxproj:2145

  • This project-level Profile setting excludes x86_64, making Profile builds on the repository's Intel environment unable to select a valid architecture. It is inconsistent with the Intel build matrix in .github/workflows/BuildPR.yml:17-22; retain that architecture or update the supported-architecture contract and CI together.
				EXCLUDED_ARCHS = x86_64;

script/update_libgit2:8

  • This mtime scan only considers files that still exist. If the libgit2 submodule is switched to a revision that deletes or renames a source file, find can return no newer file while the old archive remains present and newer than every remaining file, causing the script to exit with stale code. Track the submodule revision or another manifest/sentinel so deletions invalidate the archive.
newer_source=$(find External/libgit2 \
  \( -path 'External/libgit2/.git' -o -path 'External/libgit2/build' \) -prune -o \
  -type f -newer "$product" -print -quit 2>/dev/null || true)
  • Files reviewed: 2/2 changed files
  • Comments generated: 5
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ObjectiveGitFramework.xcodeproj/project.pbxproj Outdated
Comment thread script/update_libgit2 Outdated
Comment thread script/update_libgit2 Outdated
Comment thread ObjectiveGitFramework.xcodeproj/project.pbxproj Outdated
Comment thread script/update_libgit2 Outdated
@hannesa2

Copy link
Copy Markdown

Sorry for the late review, I miss this pull request. My bad

Comment thread ObjectiveGitFramework.xcodeproj/project.pbxproj Outdated
Comment thread ObjectiveGitFramework.xcodeproj/project.pbxproj Outdated

@goneng goneng left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

One blocker from a quick read: the four EXCLUDED_ARCHS = x86_64; additions in the build configurations.

That makes the project unbuildable on Intel Macs, and this repo still runs a macos-15-intel job in CI.

Dropping those four lines should be all it needs. The rest of the PR looks like a real improvement.

EXCLUDED_ARCHS = x86_64 was added to work around archiving on an Apple
Silicon host: ARCHS defaults to arm64 + x86_64 there, while
script/update_libgit2 builds a single-arch libgit2.a for the host, so the
x86_64 slice fails to link.

Excluding x86_64 project-wide was the wrong lever. All four settings sat on
project-level configurations, so they cascaded to every target; they
contradicted ObjectiveGit-Mac's own VALID_ARCHS = "x86_64 arm64"; and they
left the macos-15-intel CI job with no buildable architecture.

Architecture selection belongs at the invocation instead - ARCHS=, as the
workflow already passes, or ONLY_ACTIVE_ARCH, which Debug and Release
already set. Building a universal libgit2.a is not an option here because
libgit2 links Homebrew OpenSSL, which is native-arch only.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeDNs6jJrjDDdpo2T1YUDF
The mtime scan only considered files that still existed. Switching the
libgit2 submodule to a revision that deletes or renames a source could
leave every surviving file older than External/libgit2.a, so the script
reported "libgit2 is up to date." and the build linked stale code.

Replace it with a stamp file recording a key built from the submodule
revision, the submodule working tree state, the host architecture and a
hash of this script. That covers revision switches including ones that only
delete files, uncommitted edits and deletions, an archive built for the
other architecture, and changes to the cmake flags. The submodule's build
directory is excluded so its own output does not force a rebuild.

Failures are no longer masked: git errors go to stderr instead of
2>/dev/null, and any part of the key that cannot be computed yields an
empty key, which rebuilds rather than trusting an archive we cannot account
for. The stamp is removed before building and written only after the
archive is installed, so an interrupted build cannot look up to date.

The run script phase now sets alwaysOutOfDate instead of declaring
inputPaths. libgit2's sources cannot be enumerated statically, so listing
only CMakeLists.txt let Xcode skip the phase when sources changed - the
same staleness, one level up. The script's own check is now the single
source of truth, and it is cheap.

Also anchor the script to the repository root so the CI invocation and
Xcode's $SRCROOT invocation behave identically, stop the product variable
shadowing itself, and teach clean_externals and .gitignore about the stamp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeDNs6jJrjDDdpo2T1YUDF
The workflow interpolated matrix.arch, but the matrix defines abi, so both
jobs passed an empty ARCHS and neither pinned the architecture it claims to
test. Use matrix.abi, in the archive step and in the commented-out test
step so it is correct if it is re-enabled.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeDNs6jJrjDDdpo2T1YUDF
Resolves the freshness rewrite against master's switch from BUILD_CLAR to
BUILD_TESTS, and accepts master's removal of script/clean_externals, which
this branch had only touched to teach it about the build stamp.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EeDNs6jJrjDDdpo2T1YUDF

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Comment thread script/update_libgit2
Comment on lines +25 to +26
git -C "$submodule" status --porcelain --untracked-files=all \
-- . ':(exclude)build' || return 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As it's a High finding, I'll give Copilot a try ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ok, I don't do it with Copilot 😁
image

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This could be an alternative: copy&past from google

BUILD_KEY=$(
  (
    git -C "$submodule" ls-files -s -- . ':(exclude)build'
    git -C "$submodule" ls-files -o --exclude-standard -- . ':(exclude)build'
  ) | sort -u | git -C "$submodule" hash-object --stdin
) || return 1

};
D0A330F116027F2300A616FA /* libgit2 */ = {
isa = PBXShellScriptBuildPhase;
alwaysOutOfDate = 1;
# run: xcodebuild -workspace ObjectiveGitFramework.xcworkspace -scheme "ObjectiveGit Mac" test ARCHS="${{ matrix.abi }}"
- name: Archive project
run: xcodebuild -workspace ObjectiveGitFramework.xcworkspace -scheme "ObjectiveGit Mac" archive ARCHS="${{ matrix.arch }}"
run: xcodebuild -workspace ObjectiveGitFramework.xcworkspace -scheme "ObjectiveGit Mac" archive ARCHS="${{ matrix.abi }}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Indeed there was a bug !

@hannesa2 hannesa2 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

As it works, we could solve it later too. But this is just my opinion

@hannesa2
hannesa2 merged commit 61140b4 into gitx:master Sep 22, 2026
2 checks passed
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.

5 participants