> ## Documentation Index
> Fetch the complete documentation index at: https://ayakaleaf-pro.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Sync Project States Collection

`githubSyncProjectStates` holds one document per project that is linked to a GitHub repository: which repository, and where the last sync left off. It belongs to the `github-sync` web module (`services/web/modules/github-sync`). The schema is in `services/web/modules/github-sync/app/models/githubSyncProjectStates.mjs`, and all access goes through `services/web/modules/github-sync/app/src/SyncStateManager.mjs`.

#### Fields

| Field | Type | Meaning | Source |
| - | - | - | - |
| `_id` | ObjectId | Set by Mongoose on create. | |
| `projectId` | ObjectId | The linked project. Required. The schema says `unique: true`, but no index is built (see Indexes). | `githubSyncProjectStates.mjs:8` |
| `repoFullName` | String | The repository as `owner/name` (GitHub's `full_name`). Required. | `githubSyncProjectStates.mjs:9` |
| `defaultBranchName` | String | The branch the project syncs with. Set when the project is linked and not changed afterwards: on import, the branch sent by the import form; on export, the new repository's default branch. Default `null`. | `githubSyncProjectStates.mjs:10`, `GitHubSyncHandler.mjs:175-181,235-241` |
| `mergeStatus` | String | `clean`, `conflict` or `diverged`. Default `clean`. | `githubSyncProjectStates.mjs:11` |
| `lastSyncCommit` | String | The commit SHA on the synced branch at the last sync. Default `null`. | `githubSyncProjectStates.mjs:12` |
| `lastSyncVersion` | Number | The project history version at the last sync, from project-history `GET /project/:id/version`, read after a history flush. Default `null`. | `githubSyncProjectStates.mjs:13`, `services/web/modules/github-sync/app/src/HistoryManager.mjs:8-17` |
| `unmergedBranchName` | String | During a conflict: the temporary branch with the Overleaf changes, named `overleaf-YYYY-MM-DD-HHMMSS`. `null` when there is no conflict. | `githubSyncProjectStates.mjs:14`, `GitMerge.mjs:773-777` |
| `unmergedBranchHead` | String | During a conflict: the head commit of that branch. Default `null`. | `githubSyncProjectStates.mjs:15` |
| `conflictVersion` | Number | During a conflict: the project history version when the conflict was recorded. Default `null`. | `githubSyncProjectStates.mjs:16` |
| `__v` | Number | The Mongoose version key. The schema does not turn it off. | Mongoose default |

#### Who Writes It

| Code | What it does |
| - | - |
| `SyncStateManager.mjs:9-14` (`createProjectState`) | Creates the document: after importing a repository as a new project (`services/web/modules/github-sync/app/src/GitHubSyncHandler.mjs:175-181`), or after exporting a project to a new repository (`GitHubSyncHandler.mjs:235-241`, owner only, refused when already linked). |
| `SyncStateManager.mjs:16-21` (`updateProjectState`) | `$set` of the changed fields. `getMergeOverview` sets `mergeStatus: 'diverged'` when the synced branch no longer builds on `lastSyncCommit`: GitHub's compare answers `diverged` or `behind` (`GitHubApiClient.mjs:382-400`), or the commit is gone and the user can push (`GitHubSyncHandler.mjs:123,126-137`). A sync (`services/web/modules/github-sync/app/src/GitMerge.mjs`) moves `lastSyncCommit`/`lastSyncVersion` on success (for example `:143,173,224`), records a conflict with `unmergedBranchName`, `unmergedBranchHead` and `conflictVersion` (`:207-213`), and clears them once it is resolved (`:250-257`). |
| `SyncStateManager.mjs:23-25` (`removeProjectState`) | Deletes the document when the owner unlinks the project (`GitHubSyncHandler.mjs:83-97`) and when a deleted project expires (`services/web/modules/github-sync/index.mjs:56-58`). |

#### Who Reads It

| Code | What it does |
| - | - |
| `GitHubSyncHandler.mjs:39-60` (`getProjectState`) | Gives the editor `mergeStatus`, `repoFullName` and `unmergedBranchName`. With no document it answers `need-export`, a value that is never stored. |
| `GitHubSyncHandler.mjs:110-143` (`getMergeOverview`) | Compares `lastSyncCommit` and `lastSyncVersion` with GitHub and the project history to list the new commits. |
| `GitHubSyncHandler.mjs:200` (`exportProject`) | Refuses to export a project that is already linked. |
| `GitMerge.mjs:27` (`doGitMergeWithoutLock`) | Loads the state at the start of a sync. |

#### Indexes

| Name | Keys | Options | Migration |
| - | - | - | - |
| `_id_` | `_id: 1` | | default |

Mongoose `autoIndex` is off (`services/web/app/src/infrastructure/Mongoose.mjs:7`), so the schema's `unique: true` on `projectId` creates nothing. `tools/migrations/20190912145010_create_githubSyncProjectStates_indexes.mjs` (upstream's `project_id` and `owner_id`) is tagged `saas` only and does not run in CE.

#### Notes

* A sync runs under the `gitSync` lock of the project (`GitMerge.mjs:17-24`). GitLab and Gitea Sync take the same lock, so only one sync runs per project at a time.
* A deleted project keeps its document until the project expires.
* The user's GitHub token is in [GitHub Sync User Credentials](https://ayakaleaf-pro.mintlify.site/dev/data-model/github-sync-user-credentials-collection.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.