Skip to content

Latest commit

 

History

42 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

overleaf-to-git
===============

Archive an Overleaf project's *full edit history* into a local Git repository,
one commit per Overleaf revision, preserving authors, co-authors, and the
original timestamps. Overleaf offers no supported way to export this history,
so the tool reconstructs it from the same JSON endpoints the "History" tab uses
in a browser.

It works against overleaf.com and against a self-hosted Overleaf/ShareLaTeX
instance (set --base-url), which makes it handy when migrating projects to your
own server.


Install
-------

The project requires Python 3.10 or newer and is managed with `uv`
(https://docs.astral.sh/uv/):

    git clone https://github.com/zambonin/overleaf-to-git.git
    cd overleaf-to-git
    uv sync                      # core install
    uv sync --extra browser      # also enable --from-browser cookie import

Run it as a module or via the installed script:

    uv run overleaf-to-git --help
    uv run python -m overleaf_to_git --help


Authentication
--------------

No password is sent and no browser cookie database is read by default. Copy your
session cookie once from your browser's developer tools (Application -> Cookies),
the value named `overleaf_session2` on overleaf.com, and pass it in:

    export OVERLEAF_SESSION='s%3A...'        # the cookie value
    uv run overleaf-to-git --list

Alternatives:

  * `--from-browser firefox` imports cookies automatically (needs the optional
    `browser_cookie3` dependency; install with `uv sync --extra browser`).
  * Self-hosted instances usually name the cookie `sharelatex.sid`; pass
    `--base-url https://overleaf.example.org --cookie-name sharelatex.sid`.


Usage
-----

    # list projects (newest first), their owners and their dashboard tags
    uv run overleaf-to-git --list

    # archive projects 1 to 4 and 7, non-interactively
    uv run overleaf-to-git --projects "1-4 7"

    # archive exact projects reproducibly (repeat for several projects)
    uv run overleaf-to-git --project-id 59d3b117fea3c15129b60c74

    # archive every project carrying a dashboard tag (repeatable)
    uv run overleaf-to-git --tag '~published'

    # ...and file the repositories under a directory per tag
    uv run overleaf-to-git --tag '~published' --group-by-tag

    # omit --projects and --tag to pick interactively from the printed list

Each chosen project becomes a Git repository under --output-dir, which defaults
to `~/.local/share/overleaf-to-git/` ($XDG_DATA_HOME). The repositories are the
product, so they live in the data directory and never in the cache, which
anything is entitled to delete.


Re-running
----------

Repositories are named `<projectId>-<slug>` and found again by their id, so a
re-run updates the repository it made last time instead of building a second
one, and follows a project renamed on Overleaf. Only the projects that actually
changed are reported when a run finishes.

Imported commits are deterministic, so rebuilding an unchanged history
reproduces its commit ids exactly and adds nothing. Signing in UTC keeps the
importing machine's timezone out of those ids.

Commits of your own on top of the imported history are never discarded: they are
kept on a `local/<timestamp>` branch. Such a branch is deleted once a later
import turns out to contain its commits anyway.
An archive repository with uncommitted changes is rejected rather than reset;
these repositories are otherwise machine-owned.


Responsible use & caching
-------------------------

Requests are rate limited (diffs at 1/second, version ZIPs at 1/2 minutes) and
the tool backs off when the server signals a limit (HTTP 429/500, `Retry-After`)
or when the network fails, retrying with exponential backoff rather than losing
a long import to one timeout. A wait longer than a few seconds is announced with
a countdown, and Ctrl-C stops it cleanly.

The budgets are tunable, since the useful value depends on the instance and the
network: `--timeout` and `--retries` as flags, and the ZIP quota as
`OVERLEAF_ZIP_PERIOD` (seconds per ZIP; it is read before the flags exist).

Every downloaded diff and ZIP is cached under `--cache-dir` (default
`~/.cache/overleaf-to-git/<project-id>/`), so an interrupted archive resumes
without touching Overleaf's servers again for anything it already fetched.
Cache entries are validated and installed atomically; an interrupted write is
never mistaken for a completed download.
Projects are fetched and archived one at a time, so an interrupted run keeps the
projects it had already finished. Keep the cache around until you are done.

Binary files are reconstructed from version ZIPs, downloading the minimal set of
ZIPs by normalizing add/rename/remove sequences first.


Notes
-----

Files opened on Overleaf can be marked "modified" with no visible change (a user
rapidly adding then removing content); such revisions are still committed (empty
if needed) and noted in the commit message. Use `git-filter-repo` afterwards if
you want to prune or rewrite the imported history.

DISCLAIMER: this may not align with Overleaf's Acceptable Use Policy regarding
"scraping". The author's position is that Overleaf provides no supported
interface to archive your own project history; this tool merely automates what a
user could do by clicking through every revision in the History tab.

About

Python module that converts Overleaf's project histories to Git repositories.

Topics

Resources

Stars

11 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages