東京大学の松井と申します。本記事はTeX & LaTeX Advent Calendar 2024の12/15のものです。

OverleafプロジェクトのGit管理

OverleafはTeXによる論文執筆のための便利なプラットフォームです。私は近年は全ての論文をOverleafで執筆しています。一方で、Overleafは通常状態だとバックアップや更新履歴確認がやりづらいです。Gitで更新を管理し、履歴や差分の確認はGitHubのUIを使いたくなります。OverleafをGitで管理するためには、ややこしいのですがGit連携GitHub連携の二つの方法があります。本記事では、Git連携を使いつつ、その中身を自分のGitHubリポジトリ上にバックアップする方法を紹介します。

Git連携 vs GitHub連携

二つの連携方式は以下のようになり、挙動が大きく違います。

  • Git連携
    • Git(Not GitHub)で、Overleafプロジェクトを管理する。
    • Git URLが発行され、それを通してプロジェクトにアクセスできるようになる。すなわち、git clone https://git.overleaf.com/1234567 のようにしてプロジェクトの中身をcloneできるようになる。その後add, commit, push, pullなどが出来る。
    • 基本的にCUIの話。GitHubは出てこない。
  • GitHub連携
    • GitHub (Not Git)で、Overleafプロジェクトを管理する。
    • Overleafと、GitHubのアカウントがリンクされる。GitHub上にリポジトリが作られ、Overleaf上から「同期」ボタンを押すと、Overleafの更新がリポジトリに反映される。
    • ローレベルなgitコマンドは出てこない。GUI上で「同期」ボタンを押すだけという話。

Git連携のほうがローレベルに細かく管理できますが、バックアップや更新履歴確認のためにはGitHub連携のほうが簡単です。GitHub連携によるバックアップで要望を満たせているなら、それでOKです。

なぜ「GitHub連携」ではなく「Git連携+GitHub」なのか

本記事では、「Git連携だけどGitHubリポジトリ上で管理」という方式を紹介します。そのような回りくどいことをする理由は、以下の通りGitHub連携が使いづらい場面があるからです。

  • 二つのGitHubアカウントを同時に用いることが出来ない
    • 実はGitHub連携をする際には「1つのOverleafアカウントにつき1つのGitHubアカウント」をリンクします。なので、複数のOverleafプロジェクトについて、それぞれに別のGitHubアカウントを割り当てることは出来ません。これは不便な場合があります。
  • OverleafとGitHubを疎結合にしたい
    • 上とも関わる話ですが、GitHub連携の場合はGitHubとOverleafをリンクする必要があり、二つのアカウントが結びついてしまいます。本当はGitに関する処理はOverleafとは疎結合にするほうが気持ちがいいという場面があります。
  • 細かい管理ができない
    • GitHub連携は楽なのですが、GitやGitHubの機能を用いた細かい管理が簡単ではないです。例えばGitHub Actionsを用いて、論文内容が更新されるたびに何か追加処理をする、といったことをしたいかもしれません。そのような処理は、GitHub連携では不向きです。

手順1(まずは通常のGit連携)

まず準備として、Overleafの設定のページの下部の「Git Integration」のところで「Add another token」を押してトークンを発行します。トークンはabc_6fwkRselfij4jsi3RpikoREDsij7efjowRjZのような文字列で、パスワードのようなものです。これは人に見られないように保存してください。このトークンを用いてGit管理を行います。このトークンは最初に一度作っておき、各プロジェクトで使いまわせます。トークンは一年間有効のようです。トークンが切れたらもう一度発行すればOKです。

さて、それではまず、これからGit管理したいOverleafプロジェクトを作成します。このプロジェクトのURLがhttps://www.overleaf.com/project/xxxxxxxxxxxxxxであるとしましょう。ここでxxxxxxxxxxxxxxxxxxxxxの部分は今後プロジェクトIDと呼びます。

次に、そのOverleafプロジェクト上で、左上の「Menu」をクリックし、「Sync」の「Git」を選択します。すると下記のようにcloneのためのコマンドが表示されます。ここでxxxxxxxxxxxxxxxxxxxxxは、プロジェクトIDです。

$ git clone https://git@git.overleaf.com/xxxxxxxxxxxxxxxx

このコマンドを手元のターミナルで実行すると、Overleafプロジェクトの中身が手元にcloneされます。この時、最初にOverleafのトークンの入力を求められるので、先ほど発行したトークンを入力します。この手元のリポを使ってadd, commit, push, pull等を行うのが通常のGit連携の使い方です。ここで、各操作のたびにトークン入力が求められます。注意として、このgitはデフォルトブランチがmainではなくmasterになっています。

ちなみに、毎回トークンを入力するのがめんどくさい場合は、以下を実行しておくと一定時間トークンがキャッシュされるようになります。

$ git config --local credential.helper 'cache --timeout=3600'

手順2(GitHubリポジトリと同期)

手順1のGit連携により、Overleafの内容を手元にGitでバックアップできるようになりました。一方で、更新の履歴の確認などはGUIでグラフィカルに行いたい場合があります。その場合、GitHubのウェブインターフェースを使いたくなります。そのやり方を説明します。 これにはいくつかの方法があると思うのですが、試せた範囲で一番簡単なものを紹介します。

まず、手順1で手元にcloneしたものはもう使わないので、削除しておいてください。

さて、それではGitHub上で新しいリポジトリを作成します。リポジトリ作成ボタンを押して、 上の方に出てくる A repository contains all project files, including the revision history. Already have a project repository elsewhere? Import a repository. のところで Import a repository を押します。 ここで、各項目には以下を入力します。

  • The URL for your source repository
    • OverleafのGit URL。すなわち https://git.overleaf.com/xxxxxxxxxxxxxxxx のようなもの
  • Your username for your source repository
    • gitとだけ入力
  • Your access token or password for your source repository
    • 先程入手したトークン

このようにしてソース元を指定してリポジトリを作ります。これにより、Overleafの内容をコピーしたGitHubリポジトリが作られます。 よって、Overleafの中身をGitHubで管理する準備が整いました。 しかし、この段階ではGitHubの中身はOverleafのコピーにすぎず、GitHubを更新してもOverleafは更新されませんし、Overleafを更新してもGitHubは更新されません。 そこで、Overleafをremote branchとして追加することでデータをやり取りできるようにしましょう。

まず上記のGitHubリポジトリを手元に好きな方法でcloneします。今後はこの手元にcloneしたリポジトリを使って作業を行います。

$ git clone .....

次に、この手元のリポジトリにOverleafをremote branchとして追加します。以下のコマンドを実行します。これにより、GitHubとOverleafを行き来できるようになりました。xxxxxxxxxxxxxxxxxxxxxの部分はプロジェクトIDです。

$ git remote add overleaf https://git@git.overleaf.com/xxxxxxxxxxxxxxxx

Overleaf側での編集をGitHubに取り込む場合は次のようにします。これがやりたかったことです。これにより、Overleafの内容をGitHubにバックアップすることができます。ここで、originはGitHubを、overleafはOverleafを指します。

# Oveleafで編集したとする
$ git pull overleaf master  # overleafの内容を手元に反映。トークン入力が必要。
$ git push origin master    # それをgithubリポに反映。

また、次のようにして、手元の編集をGitHubおよびOverleafに反映させることもできます。

# 手元でmain.texを編集したとする
$ git add main.tex
$ git commit -m "updated main"
$ git push origin master    # githubリポに反映。
$ git push overleaf master  # overleafに反映。トークン入力が必要。

図示すると以下です。

ここで、以下が注意点になります。

  • 通常のGit連携ではoriginはOverleafですが、このやり方の場合はoriginはGitHubになっている点に注意してください。
  • Overleafとのやり取りにはトークンが必要です。GitHubとのやり取りには、GitHubで普段使っている認証方式(SSHとか)が必要です。
  • このやり方は2つのリポジトリの歴史を手動で合わせています。同期を忘れると歴史がおかしくなることがあるので注意してください。

手順3(発展編:バッジクリックで同期)

さて、手順2のやり方でOverleafをGitHubに同期させることが出来ました。しかし、そのためにはOverleafの内容を手元に一度pullしてきて、それをGitHubにpushするという手順を踏む必要があります。これはちょっとめんどくさいです。元々やりたかったことはOverleafの内容を簡単にGitHubに同期して、GitHubのインタフェースで作業履歴を確認することです。なので、もっと簡単に同期をとりたくなります。

そこで、以下のようにGitHub画面上のバッジをクリックすると、Actionsの画面に飛ぶ。その画面でRunのUIを押すと、OverleafとGitHubが同期されるという仕組みを紹介します。

この仕組みを実現するために、次のようにします。

  • Overleafの内容をpullし、GitHubにpushするCI(GitHub Actions)を設定する
  • そのActionsを手動で(ブラウザ上からクリックで)実行できるようにする
  • そのActionsを簡単に開くためのバッジを作ってREADMEに貼る

それではまずCIを設定します。手元のリポジトリ上で、.github/workflows/sync.yamlというファイルを作成し、次のようにしてください。

name: Manual pull and push

on:
  workflow_dispatch:

jobs:
  sync:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      
    steps:
    - name: Checkout repository
      uses: actions/checkout@v4

    - name: Pull from Overleaf
      env:
        OVERLEAF_TOKEN: ${{ secrets.OVERLEAF_TOKEN }}
        OVERLEAF_PROJECT_ID: ${{ secrets.OVERLEAF_PROJECT_ID }}
      run: |
        git config pull.rebase false
        git pull https://git:${OVERLEAF_TOKEN}@git.overleaf.com/${OVERLEAF_PROJECT_ID} master

    - name: Push to GitHub
      run: |
        git push origin master

このyamlそのものは、git add .github, git commit -m "CI", git push origin master, git push overleaf masterなどとしてGitHubにもOverleafにも追加しておきましょう。

このCIにより、GitHub上で手動でOverleafの中身をGitHubに同期できます。ここで、秘密情報を以下のように設定しておきます。 GitHubの画面でSettings -> Security -> Secrets and variables -> Actionsと進み、Repository secretsに以下のトークンを設定します。

  • OVERLEAF_TOKEN
    • abc_6fwkRselfij4jsi3RpikoREDsij7efjowRjZのようなもの(トークン)
  • OVERLEAF_PROJECT_ID
    • xxxxxxxxxxxxxxxxxxxxxxxのようなもの(プロジェクトID)

それでは早速CIを実行してみましょう。GitHubの画面からActionsをクリックし、左側でManual Pull and Pushをクリックし、下図のように右側のRun workflowを押して出てくる緑色のRun workflowを押してください。これによりCIが手動実行され、Overleafの内容がGitHubに同期されます。

ためしに、Overleaf上でファイルを色々変更し、その上で上記のCIを実行してみてください。その変更がGitHubに反映されることがわかります。ここで、実行途中の様子はActionsタブから確認できます。上手くいかない場合は、そこでエラーになっていることがわかるはずです。

ちなみに、上記で秘密情報を設定したのは、CIの設定ファイル上に直接トークンなどを書くべきではないからです。ここが上手くいかない場合は、秘密情報を展開した以下を手元で走らせてみて、上手くいくか確認してみてください。以下はOverleaf ProjectもTokenも指定しているので、追加情報無しでpullできるはずです。

$ git pull https://git:abc_6fwkRselfij4jsi3RpikoREDsij7efjowRjZ@git.overleaf.com/xxxxxxxxxxxxxxxxxxxxxxx master

最後に、バッジを作成して、上記のCI実行画面にすぐに遷移できるようにしましょう。上記のActionsの画面から右上の「・・・」のボタンをクリックし、Create status badgeをクリックします。すると次のようなリンクをコピーできます。

[![Manual pull and push](https://github.com/YOUR_GITHUB_NAME/YYYYY/actions/workflows/sync.yaml/badge.svg)](https://github.com/YOUR_GITHUB_NAME/YYYYY/actions/workflows/sync.yaml)

README.mdを作り、このリンクを貼っておきます。そしてREADMEをGitHubにもOverleafにもpushしてください。その後、GitHubのトップ画面を見ると次のようになるはずです。

このバッジをクリックすると先程のActionsの画面に飛びます。そして、先程と同様にRun workflowを押すことで、Overleafとの同期がとれるようになりました。このやり方は元々のGitHub連携ほど簡単ではない(GitHub連携の場合はワンクリックで同期がとれる)のですが、しかしそれでもGitHubを開いて3クリックぐらいで同期がとれます。なので、悪くはないお手軽バックアップだと思います。