How To Automatically update git submodules using GitHub Actions

Monorepo project structures with git submodules are great and easy to manage to benefit from a centralized data flow, and I personally use them for blog writing.

As an example, I’ll walk you around on how to setup a codebase to sync between two repositories, the website repo and the writings repo that holds markdown files, in my case, using the Github Actions CI/CD.

We’ll start by initializing the git submodule in my local website blog repo using:

git submodule add <https://github.com/0xWerz/writings> # <repo_you_want_to_sync_with>

This should create the repo directory.

Now on the writings repo we should create a webhook event that gets triggered each time a new push event happen to send a dispatch event to the website repo, using peter-evans/repository-dispatch@v3 to update its submodule(s)

In .github/workflows/dispatch_update.yml

name: Dispatch Update Submodule

on:
  push:
    branches:
      - main

jobs:
  dispatch:
    runs-on: ubuntu-latest

    steps:
      - name: Dispatch update to Git Blog Project
        uses: peter-evans/repository-dispatch@v3
        with:
          token: ${{ secrets.PAT }}
          repository: 0xWerz/werz
          event-type: update-submodule

This should sent a update-submodule event to the 0xWerz/werz website repo. If the repositories are private you’d need a Personal Access Token (PAT) with the the contents: write permissions.

To listen to the events sents to the website (werz) repo, we should sent up a github action workflow as well. .github/workflows/update_submodule.yml

name: Update Submodule

on:
  repository_dispatch:
    types:
      - update-submodule

jobs:
  update-submodule:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.PAT }}
          submodules: recursive

      - name: Authorize Git
        run: |
          git config --global user.email "$GITHUB_ACTOR@users.noreply.github.com"
          git config --global user.name "$GITHUB_ACTOR"

      - name: Update submodule
        run: |
          git submodule update  --init --recursive --remote -f
        env:
          GITHUB_TOKEN: ${{ secrets.PAT }}

      - name: Commit changes
        run: |
          git add writings
          git commit -m "Update submodule to latest commit"
          git push origin main

        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

This should be syncing each new push with the submodule.