GitLab Connector
unlistedby sigvis
Sync markdown files between Vaults and GitLab repositories. Supports offline editing via isomorphic-git and a lightweight REST API fallback for both mobile (Android) and desktop.
Obsidian GitLab Connector
Bi-directional sync between an Obsidian vault subfolder and a GitLab repository. Supports both offline-capable sync via isomorphic-git and lightweight online sync via the GitLab REST API.
Features
- Pull remote changes into your vault, with automatic three-way merge for non-conflicting edits
- Push local changes to GitLab with auto-generated commit messages
- Selective commit: choose exactly which files to include and write a custom commit message
- Two sync backends: full git (offline-capable, IndexedDB-based) or REST API (no local state, always online)
- Auto-sync on a timer or whenever vault files change
- Interactive conflict resolution for true merge conflicts
- All operations available from the ribbon menu or command palette
- Android support: REST API mode runs entirely in-browser with no native Node.js modules
Requirements
- Obsidian ≥ 1.11.4 (requires SecretStorage API for PAT storage)
- GitLab instance (gitlab.com or self-hosted), accessible over HTTPS
- Personal Access Token (PAT) with
read_repository+write_repositoryscopes
Note: SSH is not supported. All communication is HTTPS only.
Installation
This plugin is not yet listed in the Obsidian Community Plugins directory. Install manually:
From a release
- Go to the Releases page of this repository and download the latest release zip.
- Extract the archive — it contains
main.js,manifest.json, andstyles.css. - Copy the three files into your vault's plugin folder:
<vault>/.obsidian/plugins/obsidian-gitlab-connector/ - Reload Obsidian (or toggle the plugin off and on in Settings → Community Plugins).
From source
See Building from Source below.
Android
Android requires extra steps because the file manager does not let you write directly inside .obsidian/. Use one of these approaches:
Option A — copy via a file manager app
- Build the plugin (or download a release) on a desktop machine.
- Transfer
main.js,manifest.json, andstyles.cssto your Android device (USB, cloud storage, etc.). - Use a file manager (e.g. Files by Google, MiXplorer) to copy the three files into:
You may need to enable "show hidden files" to see<internal-storage>/<vault-name>/.obsidian/plugins/obsidian-gitlab-connector/.obsidian/. - Open Obsidian, go to Settings → Community Plugins, disable safe mode if prompted, and enable GitLab Connector.
Option B — use Termux
- Install Termux from F-Droid (not the Play Store version — that one is outdated).
- Grant Termux storage permission:
termux-setup-storage - Copy the plugin files:
VAULT="$HOME/storage/shared/YourVaultName" PLUGIN="$VAULT/.obsidian/plugins/obsidian-gitlab-connector" mkdir -p "$PLUGIN" cp main.js manifest.json styles.css "$PLUGIN/" - Restart Obsidian and enable the plugin.
Android sync mode: Use REST API mode on Android. The isomorphic-git backend is supported but requires more memory and may be slower on low-end devices. REST API mode makes direct HTTP calls to GitLab with no local git state, which is lighter and more reliable on mobile.
Building from Source
Prerequisites
- Node.js ≥ 18
- npm ≥ 9
Steps
# 1. Clone the repository
git clone https://github.com/<owner>/obsidian-gitlab-connector.git
cd obsidian-gitlab-connector
# 2. Install dependencies
npm install
# 3. Build a production bundle
npm run build
This produces main.js at the repository root. Copy main.js, manifest.json, and styles.css into your vault's plugin folder as described in Installation.
Development build (watch mode)
npm run dev
Starts esbuild in watch mode with inline source maps. Every file save triggers a rebuild. Point Obsidian's plugin folder at the repository root (or symlink it) to hot-reload during development.
Running the test suite
npm test # run once
npm run test:watch # re-run on file changes
Tests use Vitest and run entirely in Node (no browser or Obsidian runtime needed). The suite covers path translation utilities, change detection logic, and git rollback regression tests using an in-memory filesystem.
Project layout
obsidian-gitlab-connector/
├── src/
│ ├── main.ts # Plugin entry point (Obsidian Plugin class)
│ ├── polyfills/
│ │ ├── buffer.js # Buffer polyfill for Android/iOS WebView
│ │ └── node-crypto.js # Pure-JS crypto polyfill for Android
│ ├── git/
│ │ └── git-manager.ts # isomorphic-git wrapper
│ ├── sync/
│ │ ├── sync-engine.ts # Orchestrator
│ │ ├── git-sync-backend.ts
│ │ ├── api-sync-backend.ts
│ │ ├── change-tracker.ts
│ │ ├── state-manager.ts
│ │ └── conflict-detector.ts
│ └── utils/
│ ├── path.ts # Remote↔vault path translation
│ └── hash.ts # SHA-256 content hashing
├── tests/
│ ├── unit/ # Vitest unit tests + mocks + config
│ │ ├── git/git-manager.test.ts
│ │ ├── sync/change-tracker.test.ts
│ │ ├── utils/path.test.ts
│ │ ├── mocks/obsidian.ts # Minimal Obsidian stub for Node tests
│ │ └── vitest.config.mts
│ └── e2e/ # WDIO end-to-end tests + vaults + configs
│ ├── specs/
│ ├── vaults/simple/
│ ├── wdio.conf.mts
│ ├── wdio.mobile.conf.mts
│ ├── wdio.manual-setup.conf.mts
│ └── tsconfig.json
├── scripts/ # Developer scripts (e.g. start-emulator.sh)
├── main.js # Built output (committed for release)
├── manifest.json # Obsidian plugin manifest
├── styles.css # Plugin styles
└── esbuild.config.mjs # Build configuration
Configuration
Open Settings → GitLab Connector to configure the plugin.
| Setting | Description |
|---|---|
| GitLab URL | Base URL of your GitLab instance, e.g. https://gitlab.com |
| Project path | Namespace and repository, e.g. username/my-notes |
| Branch | Branch to sync against, e.g. main |
| Vault subfolder | Subfolder inside your vault that maps to the remote. Leave blank to use the vault root. |
| Remote subfolder | Subfolder inside the GitLab repo to sync. Leave blank to use the repo root. |
| Sync mode | isomorphic-git (offline-capable, clones repo locally) or REST API (lightweight, always online) |
| Sync trigger | Manual (command palette / ribbon only), File change (push on save, debounced 5 s), or Auto timer |
| Sync interval | Minutes between automatic syncs (only used when trigger is Auto timer) |
| Author name / email | Used for git commit metadata (isomorphic-git mode only) |
| Personal Access Token | Your GitLab PAT — stored in OS SecretStorage, never written to data.json |
| Clone depth | Shallow clone depth for isomorphic-git mode (default: 1). Increase if you need deeper history. |
Getting a GitLab Personal Access Token
- Go to GitLab → User Settings → Access Tokens (or Profile → Preferences → Access Tokens on older versions).
- Click Add new token.
- Give it a name, set an expiry, and select the
read_repositoryandwrite_repositoryscopes. - Click Create personal access token and copy the value into the plugin settings.
Commands
All commands are available in the command palette (Ctrl/Cmd + P → "GitLab Connector:…") and from the ribbon menu (click the git icon in the left sidebar).
Pull from remote
Fetches the latest state from GitLab and applies remote changes to your vault.
- Files added or modified on remote are written to the vault.
- Remote deletions are confirmed with a modal before applying locally.
- Files changed on both sides are passed through a three-way merge:
- Non-overlapping edits are merged automatically.
- True conflicts open an interactive resolution modal.
Push to remote
Detects all locally-changed files (added, modified, deleted) and pushes them to GitLab in a single commit with an auto-generated message like vault sync: 2 modified, 1 created.
Full Sync
Pull then push — equivalent to running Pull followed by Push. This is the most common operation for keeping both sides in sync.
Commit and Push Selected Files
Opens a modal showing all locally-changed files with checkboxes. You can:
- Select or deselect individual files
- Write a custom commit message
- Confirm to push only the selected subset
This is useful when you want to commit specific changes with meaningful messages rather than pushing everything at once.
Initialize connection
Resets the plugin state and re-runs the full initialization flow. Use this if:
- You changed the GitLab URL, project, or branch settings
- You want to reset to a clean state after an error
- You switched sync mode (isomorphic-git ↔ REST API)
On first initialization (or after a reset), a modal asks whether to pull the remote contents into your vault or push your local vault contents to GitLab.
Ribbon Menu
Clicking the git icon in the left sidebar opens a dropdown menu with all available operations:
- Pull — pull remote changes
- Push — push local changes
- Full Sync — pull then push
- Commit & Push Selected Files — selective commit modal
- Re-initialize — reset and re-run setup
Sync Modes
isomorphic-git (default on desktop)
- Clones the entire repository (shallow, configurable depth) into IndexedDB (LightningFS) — completely invisible to Obsidian's file indexer
- Reads and writes git objects directly; no
.gitfolder appears in your vault - Supports offline commits: changes are committed locally and pushed when online
- On every pull, fetches the latest commits and fast-forwards the local branch
REST API (recommended on Android)
- No local git state — every operation is a direct HTTP call to GitLab
- Simpler and uses less storage, but requires network access for every operation
- Uses the GitLab Commits API to push batches of changes in a single request
- Suitable for simple use cases where offline sync is not needed, and the best choice for Android
Conflict Resolution
When the same file has been changed both locally and on the remote since the last sync, the plugin performs a three-way merge using the saved base content (the file content at last sync) as the merge ancestor.
Auto-mergeable: changes are in different parts of the file — merged silently.
True conflict: changes overlap — an interactive modal opens showing:
- The base (last-synced) content
- The local version
- The remote version
- A unified diff of each side's changes
Resolution options:
- Keep local — discard remote changes
- Keep remote — discard local changes
- Use merged — accept the auto-merge attempt (if available)
- Edit manually — close the modal and resolve the file yourself, then push again
Limitations
- HTTPS only — SSH is not supported
- No delta sync — all file content is transferred on every change detection cycle
- Requires Obsidian ≥ 1.11.4 for secure PAT storage
- Binary files are not synced — only
.mdfiles - isomorphic-git mode uses a shallow clone; very deep git history may not be accessible
Troubleshooting
"Failed to fetch" or network errors
- Verify the GitLab URL is correct and reachable from your device
- Check that your PAT has not expired
- On self-hosted GitLab, ensure the instance is accessible over HTTPS
"Push rejected — remote has new changes"
- Run Pull (or Full Sync) first to incorporate remote changes, then push again
"Nothing to push — no local changes detected"
- All local files match the last-synced state; no action needed
"Initialization failed"
- Check that all required settings (URL, project path, branch, PAT) are filled in
- Run Initialize connection from the command palette or ribbon menu to retry
Modal appears on every startup asking Pull or Push
- This happens if the sync state was never saved (e.g. you cancelled the first-run modal)
- Select a direction and complete the first sync; the modal will not appear again
Commit modal appears unstyled
- Ensure
styles.cssis present alongsidemain.jsin the plugin folder
Android: "Attempting to load NodeJS package"
- Switch to REST API sync mode in settings — isomorphic-git mode makes a best-effort attempt to polyfill Node built-ins, but REST API mode avoids all Node dependencies entirely
For plugin developers
Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.