Obsidian + Github Actions
Obsidian Sync alternative?
Section 1 - Background
I use Obsidian as my note taking app of choice.
For a time I bought into the Sync membership which worked really well.
There was a few issues however: - Synced everything which made my mobile experience slow. - I only needed a small portion of notes. - I was only using my vault on my desktop as a result of it being slow on mobile - I was paying for not really using Sync….
I could just use a Cloud service to sync my notes but as I am cross platforms, that doesn’t always make it easy. I also don’t want my notes in the Cloud, clogging up space when they can be locally.
This lead me to look for solutions.
Initally I was just using Git to make sure my notes were backed up and I had version history but it didn’t provide a ‘Sync’ where I could only sync a specific folder. Syncthing was unfortunately off the cards due to OS limitations.
But then I got to thinking…
Section 2 - Github Actions
Key words
CI/CD = Continuous integration and continuous delivery repo = Repository
In Git you have the ability to automate the running of tests, application builds, notifications etc.
After watching some Ben Vallack’s Youtube videos and getting inspired to use AI to create my own things I thought why couldn’t I use Github Actions to sync a specific folder between two repositories, automatically. Essentailly creating my Obsidian Sync.
This so far has worked really well and allows me to have a lightweight vault on my phone and tablet, allowing me to take the full advantages of Obsidian without the heft of my ‘main vault’.
Section 3 - How.
Github actions uses yaml or yml format which is two spaces for every indentation.
-
Create two Github repos, one repo will be for your ‘main vault’ and the second will be your ‘mboile vauilt’
-
Once created, select the Actions tab on your repo.
- Select ‘Set up a workflow yourself’
name: Sync Mobile to Desktop (Last-Write-Wins)
on:
push:
paths:
- '' # Path to the folder you wish to Sync.
workflow_dispatch:
repository_dispatch:
types: [sync-from-desktop]
jobs:
sync:
runs-on: ubuntu-latest
# Allows manaul triggers, cross-repo triggers and blocks auto-sync commits.
if: |
github.event_name == 'workflow_dispatch' ||
github.event_name == 'repository_dispatch' ||
(github.event_name == 'push' && !contains(github.event.head_commit.message, '[auto-sync]'))
steps:
- name: Checkout mobile repo
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GH_TOKEN }}
- name: Configure Git
run: |
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Clone and sync with desktop repo
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
# Clone desktop vault
git clone https://${GH_TOKEN}@github.com/YOUR_USER/YOUR_Repo.git desktop-temp
cd desktop-temp
# Create a branch for our changes
git checkout -b sync-from-mobile
# Copy files from mobile to desktop
rsync -av --delete --exclude='.*' ../satellite/ ./satellite/
# Check if there are changes
if [[ -z $(git status -s) ]]; then
echo "No changes to sync"
exit 0
fi
# Stage all changes
git add .
# Commit changes
git commit -m "[auto-sync] Sync from mobile vault"
# Try to merge with main
git fetch origin main
git checkout main
git pull origin main
# Attempt to merge our sync branch
if git merge sync-from-mobile --no-edit; then
echo "Clean merge successful"
git push origin main
else
echo "⚠️ MERGE CONFLICT DETECTED - Using last-write-wins strategy"
# Get list of conflicted files
CONFLICTED_FILES=$(git diff --name-only --diff-filter=U)
echo "Conflicted files:"
echo "$CONFLICTED_FILES"
CONFLICT_SUMMARY=""
for file in $CONFLICTED_FILES; do
if [[ -f "$file" ]]; then
# Get timestamps for both versions
# Mobile version (from our branch)
git show sync-from-mobile:"$file" > /tmp/mobile-version 2>/dev/null || continue
MOBILE_TIME=$(stat -c %Y /tmp/mobile-version 2>/dev/null || stat -f %m /tmp/mobile-version)
# Desktop version (from main)
git show main:"$file" > /tmp/desktop-version 2>/dev/null || continue
DESKTOP_TIME=$(stat -c %Y /tmp/desktop-version 2>/dev/null || stat -f %m /tmp/desktop-version)
echo "File: $file"
echo " Mobile timestamp: $MOBILE_TIME"
echo " Desktop timestamp: $DESKTOP_TIME"
if [[ $MOBILE_TIME -gt $DESKTOP_TIME ]]; then
echo " → Mobile version is newer, keeping mobile"
# Only create backup for the losing version (desktop in this case)
BACKUP_FILE="${file}.desktop-backup-$(date +%Y%m%d-%H%M%S)"
git show main:"$file" > "$BACKUP_FILE" 2>/dev/null || true
git checkout --ours "$file"
git add "$file" "$BACKUP_FILE"
CONFLICT_SUMMARY="${CONFLICT_SUMMARY}\n- $file: Mobile version kept (newer), desktop backed up"
else
echo " → Desktop version is newer, keeping desktop"
# Only create backup for the losing version (mobile in this case)
BACKUP_FILE="${file}.mobile-backup-$(date +%Y%m%d-%H%M%S)"
cp /tmp/mobile-version "$BACKUP_FILE" 2>/dev/null || true
git checkout --theirs "$file"
git add "$file" "$BACKUP_FILE"
CONFLICT_SUMMARY="${CONFLICT_SUMMARY}\n- $file: Desktop version kept (newer), mobile backed up"
fi
rm -f /tmp/mobile-version /tmp/desktop-version
fi
done
# Complete the merge
git commit -m "[auto-sync] Merge from mobile (conflicts resolved via last-write-wins)"
git push origin main
# Create an issue to notify about conflicts
echo "Creating notification issue about conflicts..."
gh issue create \
--title "⚠️ Sync Conflicts Resolved (Last-Write-Wins)" \
--body "Conflicts were detected and resolved using last-write-wins strategy:${CONFLICT_SUMMARY}" \
--label "sync-conflict" 2>/dev/null || echo "Could not create issue"
fi
cd ..
rm -rf desktop-temp
- name: Trigger desktop repo to sync back
if: success() && github.event_name != 'repository_dispatch'
env:
GH_TOKEN: ${{ secrets.GH_TOKEN }}
run: |
curl -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/0llieJ/ObsidianRepo/dispatches \
-d '{"event_type":"sync-from-mobile"}'
-
Reverse the code so it applies for the Desktop so when the desktop vault makes a change, that will get pushed to the mobile repo.
-
Configure a Github Access Token with the correct permissions.
- repo (Full scope)
- workflow (Full scope)
-
Setup Obsidian Git plugin to sync your changes.
Conclusion
This is has been relatively new to me, but seems to be working well and provides all the sync features I need for free, minus anything I don’t need. You can always expand the folder you want to include and sync, by adding new lines with relavant folder paths and updating the rsync line.
See you in the next one!