How to sync between Overleaf projects and Emacs

My collaborators and I have a few shared projects in Overleaf. It provides a few options to sync local and remote changes in project files. At this moment, using git to sync files is the only “free” option, but it requires users to manually sync files. I edit TeX files locally using Emacs, and use Magit to sync. Sometimes I forget to commit and push local changes to Overleaf, which can cost me a long to compare my local changes with changes in Overleaf updated by collaborators. I made a chain of commands to do semi-automatic synchronization of Overleaf projects in Emacs. It pushes local changes to Overleaf on saving TeX files. I need to do magit pull manually before editing project files, and that’s why I called this “semi-” automatic.

To use this method, I need to put the below in .dir-locals.el of the project. This directory local variable enables running 'jyun/magit-update-overleaf whenever a TeX file belongs to the project is saved.

((latex-mode . ((after-save-hook . jyun/magit-update-overleaf))))

The below is the function defined in my config.el. It uses find-file-in-project to determine the top-level directory of the current project. The function triggers to run update-overleaf.sh if it detects any changes in local files being tracked.

;;;###autoload
(defun jyun/magit-update-overleaf ()
  "Use Magit to stage files if there are unstaged ones.
Run a shellscript to commit and push staged files (if exist) to Overleaf.
 Assign a name to a shell command output buffer."
  (interactive)
  (progn
    (unless (featurep 'find-file-in-project) (require 'find-file-in-project))
    (when (or (magit-anything-unstaged-p) (magit-anything-staged-p))
      (magit-with-toplevel
        (magit-stage-1 "--u" magit-buffer-diff-files))
      (message "Asynchronously pushing changes to Overleaf...")
      (async-shell-command (format "sh %supdate-overleaf.sh" (ffip-project-root))
                           (format "*overleaf: %s*" (projectile-project-name))
                           (format "*overleaf error: %s*" (projectile-project-name)))
      ;; (message "Done!")
      )
    ))

Finally, the below is update-overleaf.sh resided in in the project root. It generate the commit message and push to Overleaf.

#!/bin/sh

# If a command fails then the push stops
set -e

printf "\033[0;32mPushing updates to Overleaf...\033[0m\n"

## this has done by Magit!
# Add changes to git.
# git add main.tex

# Commit changes.
msg="updates $(date)"
if [ -n "$*" ]; then
    msg="$*"
fi
git commit -m "$msg"

# Push source to Overleaf
git push origin master

So far, this method works well. LaTeX files are saved when compiled, so the compiling triggers pushing changes to Overleaf. It would be a good idea to write codes for triggering git pull when the project is first opened in Emacs.

Jonghyun Yun
Jonghyun Yun
Data scientist

Data scientist