How Lepton Detects and Resolves Sync Conflicts with GitHub Gists
Lepton employs a snapshot-and-compare strategy that captures UI state before syncing, compares gist timestamps to identify remote changes, and validates active tags after updates to gracefully detect and resolve sync conflicts with GitHub Gists.
Lepton is an open-source snippet manager built on Electron that synchronizes user code snippets with GitHub Gists. When remote changes occur on GitHub's servers, the application must reconcile its local cache to maintain data consistency. This article examines the specific strategies Lepton uses to detect and resolve sync conflicts with GitHub Gists, based on the implementation in app/index.js and related modules.
The Snapshot-and-Compare Architecture
Lepton's conflict detection relies on three coordinated mechanisms that work together during the synchronization cycle.
Capturing Pre-Sync UI State (app/index.js lines 74-78)
Before initiating any network requests, Lepton records the current UI context in a preSyncSnapshot object. This snapshot stores the active gist ID and the currently selected tag, preserving the user's context before remote data potentially invalidates these references.
const preSyncSnapshot = {
activeGistId: reduxStore.getState().activeGistId,
activeGistTag: reduxStore.getState().activeGistTag
}
Timestamp-Based Change Detection (app/index.js lines 112-115)
When the updateUserGists function retrieves the full list of gists from GitHub, it performs a critical timestamp comparison. For each gist returned by the API, Lepton checks the updated_at field against the cached version. If the timestamps match, the local detailed content is preserved, avoiding unnecessary overwrites. If they differ, the new remote data replaces the local cache, implicitly resolving the conflict in favor of the server state.
if (preGist && preGist.details &&
preGist.details.updated_at === gist.updated_at) {
gists[gist.id] = Object.assign(gists[gist.id], {
details: preGist.details
})
}
Conflict Resolution Mechanisms
Once changes are detected, Lepton applies specific resolution strategies to maintain UI consistency.
Remote-First Resolution Strategy
Lepton does not implement automatic merge logic for divergent content. Instead, it follows a remote-first approach: when timestamp comparisons reveal that a gist has been modified on GitHub since the last sync, the local cache is completely replaced with the remote version. This strategy assumes that the server state is authoritative, eliminating complex merge conflicts at the cost of potentially overwriting local changes that weren't yet synced.
Local edits are handled differently through immediate synchronization. When a user modifies a snippet locally, Lepton calls editSingleGist in app/utilities/githubApi/index.js to push changes to GitHub immediately, ensuring that local and remote states remain synchronized without intermediate conflicts.
Active Tag Validation and Fallback (app/index.js lines 85-95)
After the sync completes, Lepton validates whether the UI can maintain its previous context. Using the getEffectiveActiveGistTagAfterSync function, it checks if the preSyncSnapshot.activeGistTag still exists in the updated tag map. If the tag has been deleted or renamed remotely, Lepton falls back to the "All" tag, preventing the UI from referencing stale or non-existent categories.
function getEffectiveActiveGistTagAfterSync (gistTags, newActiveTag) {
if (!gistTags || !gistTags[preSyncSnapshot.activeGistTag]) {
return newActiveTag
}
return preSyncSnapshot.activeGistTag
}
Code Implementation Details
The synchronization logic centers on the updateUserGists function in app/index.js. This orchestrator manages the entire conflict detection flow, from capturing the pre-sync snapshot to resolving active tag references.
function updateUserGists (userLoginId, token) {
reduxStore.dispatch(updateGistSyncStatus('IN_PROGRESS'))
return getGitHubApi(GET_ALL_GISTS)(token, userLoginId)
.then((gistList) => {
const preGists = reduxStore.getState().gists
const gists = {}
gistList.forEach(gist => {
// ... tag and language processing ...
// ----- Conflict detection -----
const preGist = preGists[gist.id]
if (preGist && preGist.details &&
preGist.details.updated_at === gist.updated_at) {
// No change → keep existing detailed data
gists[gist.id] = Object.assign(gists[gist.id], {
details: preGist.details
})
}
})
// UI-state reconciliation based on snapshot
updateActiveGistTagAfterSync(gistTags, activeTagCandidate)
// ...
})
}
Supporting this workflow are specialized Redux reducers that track synchronization metadata. The reducer_gist_sync_status.js manages the current sync state (IN_PROGRESS, DONE) used to render progress indicators, while reducer_sync_time.js stores the human-readable timestamp of the last successful synchronization for display in the UI.
Summary
Lepton implements a deterministic, lightweight approach to detect and resolve sync conflicts with GitHub Gists:
- Pre-sync snapshots capture UI context in
app/index.js(lines 74-78) to preserve user selections before remote data arrives. - Timestamp comparison detects remote changes by matching
updated_atfields (lines 112-115), avoiding unnecessary overwrites when data hasn't changed. - Remote-first resolution replaces local cache with server state when timestamps differ, eliminating complex merge logic by treating GitHub as the authoritative source.
- Active tag validation ensures UI consistency after sync by falling back to the "All" tag when previously selected tags no longer exist (lines 85-95).
Frequently Asked Questions
How does Lepton detect when a GitHub Gist has been modified remotely?
Lepton compares the updated_at timestamp from the GitHub API response with the cached version stored locally in the Redux state. If the timestamps differ, the gist has been modified remotely and the local cache is updated with the new data. This detection occurs in the updateUserGists function in app/index.js during the full refresh cycle.
Does Lepton merge conflicting changes between local and remote versions?
No, Lepton does not implement automatic merge logic for divergent content. It follows a remote-first resolution strategy where the server state always takes precedence when timestamp comparisons indicate a remote change. Local edits are pushed immediately to GitHub via the editSingleGist API call in app/utilities/githubApi/index.js, minimizing the window for conflicts.
What happens to the UI state if the currently selected tag is deleted during a sync?
If the active tag selected before the sync no longer exists in the updated tag map (because all associated gists were removed or renamed remotely), Lepton automatically falls back to the "All" tag. This validation occurs in the getEffectiveActiveGistTagAfterSync function in app/index.js (lines 85-95) to prevent the UI from referencing stale or invalid categories.
Where does Lepton store synchronization status and timing information?
Lepton uses dedicated Redux reducers to track sync metadata. The reducer_gist_sync_status.js file manages the current synchronization state (IN_PROGRESS, DONE) used to render UI progress bars, while reducer_sync_time.js stores the human-readable timestamp of the last successful sync for display in the interface.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →