Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

git-overleaf

CICoverage

Native C CLI for git-overleaf. The current version is the initial v0.1.0 release.

  • auth: save a raw Overleaf Cookie header or import one from Firefox
  • list: list projects visible to the current cookie
  • clone: download a project snapshot into a new Git repo
  • init: bind an existing Git repo to an Overleaf project
  • status: inspect cached synchronization and recovery state
  • fetch: refresh the cached remote snapshot without touching local work
  • pull: merge the latest Overleaf snapshot into the current branch
  • push: upload committed HEAD, optionally replacing remote changes
  • reset: move the branch to the cached remote snapshot

Not implemented yet:

  • webdriver/browser authentication

Build And Test

Build and runtime dependencies:

  • C11 compiler
  • cmake
  • pkg-config
  • libcurl
  • jansson
  • sqlite3
  • git
  • unzip

Additional dependencies for building and running the tests:

  • C++17 compiler
  • GoogleTest (googletest / libgtest-dev)

Coverage additionally requires gcovr.

Install dependencies:

The commands below install the complete build-and-test toolchain. For a CLI-only build, GoogleTest and a separate C++ compiler are not required.

macOS (Homebrew):

xcode-select --install # C/C++ compiler (Clang), if not already installed
brew install cmake pkgconf curl googletest jansson sqlite git unzip

Fedora:

sudo dnf install -y \
gcc \
gcc-c++ \
make \
cmake \
pkgconf-pkg-config \
libcurl-devel \
gtest-devel \
jansson-devel \
sqlite-devel \
git \
unzip

Ubuntu:

sudo apt-get update
sudo apt-get install -y \
build-essential \
cmake \
pkg-config \
libcurl4-openssl-dev \
libgtest-dev \
libjansson-dev \
libsqlite3-dev \
git \
unzip

Build the CLI without tests (no C++ compiler or GoogleTest required):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DBUILD_TESTING=OFF
cmake --build build

Run:

./build/git-overleaf --help

Build and run the tests (requires a C++17 compiler and GoogleTest):

cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Debug \
-DBUILD_TESTING=ON
cmake --build build
ctest --test-dir build --output-on-failure

Coverage:

cmake -S . -B build-coverage \
-DCMAKE_BUILD_TYPE=Debug \
-DGIT_OVERLEAF_ENABLE_COVERAGE=ON
cmake --build build-coverage --target coverage

Usage

Save cookies:

./build/git-overleaf auth \
--cookie 'connect.sid=...; overleaf_session=...' \
--cookie-file ~/.git-overleaf-cookies

Import cookies from Firefox:

./build/git-overleaf auth --from-firefox

Target a self-hosted Overleaf instance:

./build/git-overleaf --url https://latex.example.edu list

Clone a project:

./build/git-overleaf clone --project-id PROJECT_ID --project-name 'Project Name'

Bind and synchronize an existing repo:

./build/git-overleaf init --project-id PROJECT_ID --repo /path/to/repo
./build/git-overleaf status --repo /path/to/repo
./build/git-overleaf fetch --repo /path/to/repo
./build/git-overleaf pull --repo /path/to/repo
./build/git-overleaf push --repo /path/to/repo

status uses only local Git refs and config, so it needs neither a cookie nor network access. It reports the relationship among the synchronization base, committed HEAD, and the last fetched remote snapshot, plus worktree and pending recovery state.

fetch downloads the current Overleaf snapshot and updates only the last-observed remote ref. It never changes HEAD, the index, the worktree, the synchronization base, or pending recovery state. fetch --force and fetch -f are accepted for Git command-line familiarity but have the same non-destructive behavior.

Like git pull, pull allows staged, unstaged, and untracked local changes when Git can merge without overwriting them. Non-overlapping changes remain in the worktree. If incoming changes would overwrite local changes, Git rejects the merge and leaves them intact; the remote snapshot is fetched, but no pending pull is recorded. Commit, stash, or move the overlapping changes and retry.

If a pull produces merge conflicts, resolve and commit them before running push. Use pull --abort to abort the active merge and clear the pending pull. Stale, uncommitted pending-pull metadata can also be cleared this way; an already committed merge must instead be pushed, updated with another pull, or discarded explicitly with reset.

Clone and init register a branchless logical remote named overleaf by default. Choose another name at creation time with --remote NAME. For a repository created by an older version, migrate it without network access:

./build/git-overleaf register-remote --repo /path/to/repo
# If a real remote named overleaf already exists:
./build/git-overleaf register-remote --remote overleaf-project \
--repo /path/to/repo

The logical remote has no URL, push URL, branch, or refspec. Normal remotes such as origin remain ordinary Git remotes. git remote rename and git remote remove work normally, and a removed logical remote is not automatically recreated.

Reset the current branch to the last fetched snapshot without network access:

./build/git-overleaf reset --repo /path/to/repo
./build/git-overleaf reset --hard --repo /path/to/repo

Like git reset, the default mode is mixed: it moves the branch and resets the index while leaving tracked worktree content as unstaged changes. --hard also resets tracked worktree files. Both modes preserve untracked and ignored files, save the previous HEAD under refs/git-overleaf/backups/, and clear pending sync state only after the reset succeeds.

Push or force-push Overleaf from a bound repo:

./build/git-overleaf push --repo /path/to/repo
./build/git-overleaf push --force-with-lease --repo /path/to/repo
./build/git-overleaf push --force --repo /path/to/repo

Push always uploads the tree of committed HEAD; it never stages or commits worktree changes. Normal push and --force-with-lease both compare the current Overleaf content snapshot with the recorded synchronization base and reject independent remote changes. This is a content-snapshot lease, not an atomic Git ref lease. --force (or -f) replaces remote content with committed HEAD even when the snapshots have diverged.

Before uploading, push journals the remote base and exact target commit. If an upload is interrupted, another normal push resumes only when HEAD is still the target and every remote path matches either the old base or the target. Use pull to reconcile an independently changed or partially uploaded remote, or push --force to replace it intentionally. Pending state is cleared only after a completed push, successful reconciliation, abort, or reset.

Notes

The Firefox importer reads profiles.ini, copies cookies.sqlite plus any readable -wal / -shm sidecar files to a temporary directory, and imports only valid Overleaf session cookies for the configured host.

Repository metadata lives in local Git config:

  • git-overleaf.projectId
  • git-overleaf.projectName
  • git-overleaf.url
  • git-overleaf.baseRef
  • git-overleaf.remoteRef
  • git-overleaf.pendingAction
  • git-overleaf.pendingRemoteCommit
  • git-overleaf.pendingTargetCommit
  • git-overleaf.remoteFetchedAt

The logical remote uses this local-only Git config schema:

[remote "overleaf"]
gitOverleafProjectId=PROJECT_IDskipFetchAll=trueskipDefaultUpdate=true
[git-overleaf]
remoteRef=refs/git-overleaf/remote

The reserved synchronization base is refs/git-overleaf/base; the latest successfully observed snapshot is refs/git-overleaf/remote. The internal metadata file .git-overleaf-sync.json is removed from downloaded snapshots before Git comparisons.

Security

The cookie file contains live Overleaf session credentials. auth writes it with mode 0600, but it should still stay outside Git repositories and logs.

About

native C command-line client for git-overleaf

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages