Optimize GitHub sync functionality by using lastSyncedState instead of remote pulls
Problem
The current GitHub sync functionality is inefficient because it:
- Pulls from remote before comparing changes, even when
lastSyncedStateis available locally - Pushes all files in a changeset, regardless of whether they actually changed
- Makes unnecessary API calls that increase sync time and API usage
This differs from the approach in PR #3402 and instead leverages the lastSyncedState stored in the application state to determine what files have actually changed.
Solution
This PR implements a GitHub-specific optimization that:
🎯 Eliminates unnecessary remote pulls
- Uses
lastSyncedStatestored locally to determine what has changed - Only pulls from remote when
lastSyncedStateis unavailable or invalid
📁 Implements file-level change detection
- New
determineFileChanges()utility compares current state withlastSyncedState - Identifies exactly which files need to be created, updated, or deleted
- Supports both single-file and multi-file repository structures
⚡ Optimizes push operations
- Only includes changed files in the GitHub push changeset
- Properly handles file deletions for removed token sets
- Falls back gracefully to regular sync when optimization isn't applicable
Key Changes
Core Implementation
-
src/utils/determineFileChanges.ts- New utility for file-level change detection -
src/storage/GithubTokenStorage.ts- AddedwriteChangesetOptimized()method -
src/app/store/providers/github/github.tsx- Integrated optimization into push flow -
src/selectors/index.ts- Export missingtokenFormatSelector
Testing
- Comprehensive unit tests for
determineFileChanges()(87% coverage) - Integration tests validating the complete optimization flow
- All existing GitHub storage tests continue to pass
- Verified other storage providers (GitLab, Bitbucket, ADO) are unaffected
Examples
Multi-file optimization
// Before: Pushes all files + pulls remote tree
await storage.writeChangeset(allFiles, message, branch);
// After: Only pushes changed files, no remote pull needed
const fileChanges = determineFileChanges(tokens, themes, format, lastSyncedState, path, isMultiFile, isSingleFile);
if (fileChanges.hasChanges) {
await storage.writeChangesetOptimized(onlyChangedFiles, message, branch, false, fileChanges.filesToDelete);
}
Change detection logic
// Detects new token sets
expect(fileChanges.filesToCreate).toContain('tokens/semantic.json');
// Detects updated files
expect(fileChanges.filesToUpdate).toContain('tokens/global.json');
// Detects files to delete
expect(fileChanges.filesToDelete).toContain('tokens/oldTokenSet.json');
Performance Impact
- Reduced GitHub API calls by eliminating pre-push remote tree fetching
- Minimized data transfer by only sending files that actually changed
- Faster sync times especially for large repositories with many token files
- Better user experience with reduced loading times during push operations
Backward Compatibility
- ✅ Maintains full backward compatibility
- ✅ Falls back to regular sync when optimization cannot be applied
- ✅ No changes to other storage providers (GitLab, Bitbucket, ADO)
- ✅ No breaking changes to existing APIs
Testing
# Run optimization-specific tests
npm test -- --testPathPattern="(determineFileChanges|GithubOptimization)"
# Verify GitHub storage functionality
npm test -- --testPathPattern="GithubTokenStorage"
# Ensure build still works
npm run build:dev
All tests pass with 39/39 ✅ and the build compiles successfully.
💬 Share your feedback on Copilot coding agent for the chance to win a $200 gift card! Click here to start the survey.
⚠️ No Changeset found
Latest commit: 3dfc3f2f2a3f5a6c4a712bcc4c878013c22484d8
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR