Skip to content

Instantly share code, notes, and snippets.

@princeppy
Last active April 16, 2026 12:01
Show Gist options
  • Select an option

  • Save princeppy/5d4f3799c7c82d5ada52255558f7eb77 to your computer and use it in GitHub Desktop.

Select an option

Save princeppy/5d4f3799c7c82d5ada52255558f7eb77 to your computer and use it in GitHub Desktop.
Describes how to set up automatic submodule updates so that when someone pushes to the submodule repository, the parent repository automatically pulls the latest submodule reference and pushes it.

Auto-Pull Submodule from Remote

This document describes how to set up automatic submodule updates so that when someone pushes to the submodule repository, the parent repository automatically pulls the latest submodule reference and pushes it.

Overview

Push to submodule repo (main branch)
  |
  v
GitHub Action in submodule repo (notify-parent.yml)
  → sends repository_dispatch event to parent repo
  |
  v
GitHub Action in parent repo (update-submodule.yml)
  → checks out the target branch (e.g., Staaging)
  → pulls latest submodule ref
  → commits the updated pointer
  → pushes to that branch
  |
  v
Odoo.sh picks up the new commit automatically

Repositories

Role Repository SSH URL
Parent odoo_sh_dunecrest git@github.com:MantleInternational/odoo_sh_dunecrest.git
Submodule odoo_sh_dunecrest_crm git@github.com:MantleInternational/odoo_sh_dunecrest_crm.git

Prerequisites

  • You are an admin of the GitHub organization (MantleInternational)
  • Both repositories are set up with the submodule relationship (.gitmodules exists in the parent)
  • You are on the main branch of the parent repo (the workflow file must live on the default branch)

Step 1: Create a GitHub Personal Access Token (Fine-Grained)

  1. Go to github.com -> click your profile picture (top-right) -> Settings
  2. Scroll to Developer settings (bottom of left sidebar)
  3. Click Personal access tokens -> Fine-grained tokens -> Generate new token
  4. Configure:
    • Token name: odoo_sh_dunecrest_crm-auto-update
    • Expiration: 1 year (or your preference)
    • Resource owner: MantleInternational
    • Repository access: Select "Only select repositories" -> choose both:
      • MantleInternational/odoo_sh_dunecrest
      • MantleInternational/odoo_sh_dunecrest_crm
    • Permissions:
      • Contents: Read and Write
  5. Click Generate token
  6. Copy the token immediately -- you will not see it again

Approve the token at the organization level

Fine-grained tokens for organization repos may require org-level approval:

  1. Go to github.com/organizations/MantleInternational/settings/personal-access-tokens/active
  2. Find the token odoo_sh_dunecrest_crm-auto-update
  3. If it shows as pending, click to approve it

Important: Store this token securely. You will paste it into two GitHub repository secrets in the next steps.


Step 2: Add the Token as a Secret to the Submodule Repo

The submodule repo needs the token to trigger the parent repo's workflow.

  1. Go to github.com/MantleInternational/odoo_sh_dunecrest_crm
  2. Click Settings -> Secrets and variables -> Actions
  3. Click New repository secret
    • Name: PARENT_REPO_TOKEN
    • Secret: paste the token from Step 1
  4. Click Add secret

Step 3: Add the Token as a Secret to the Parent Repo

The parent repo needs the token to clone the private submodule and push the updated reference.

  1. Go to github.com/MantleInternational/odoo_sh_dunecrest
  2. Click Settings -> Secrets and variables -> Actions
  3. Click New repository secret
    • Name: PARENT_REPO_TOKEN
    • Secret: paste the same token from Step 1
  4. Click Add secret

Step 4: Create the Workflow File in the Submodule Repo

This workflow runs whenever someone pushes to the main branch of the submodule. It sends a repository_dispatch event to the parent repo, which triggers the parent's workflow.

Create the file .github/workflows/notify-parent.yml in the submodule repo (odoo_sh_dunecrest_crm):

name: Notify Parent Repo
on:
  push:
    branches: [main]

jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger parent repo update
        run: |
          curl -X POST \
            -H "Accept: application/vnd.github+json" \
            -H "Authorization: Bearer ${{ secrets.PARENT_REPO_TOKEN }}" \
            https://api.github.com/repos/MantleInternational/odoo_sh_dunecrest/dispatches \
            -d '{"event_type":"submodule-updated"}'

What this does:

  • Triggers on any push to main in the submodule repo
  • Sends an HTTP POST to the GitHub API, telling the parent repo that the submodule was updated
  • Uses the PARENT_REPO_TOKEN secret to authenticate the API call

Commit and push this file:

cd odoo_sh_dunecrest_crm
git checkout main
git add .github/workflows/notify-parent.yml
git commit -m "ci: notify parent repo on push to main"
git push origin main

Step 5: Create the Workflow File in the Parent Repo

This workflow runs when it receives the repository_dispatch event from the submodule. It pulls the latest submodule reference, commits the change, and pushes.

Create the file .github/workflows/update-submodule.yml in the parent repo (odoo_sh_dunecrest) on the main branch:

name: Update Submodule
on:
  repository_dispatch:
    types: [submodule-updated]

jobs:
  update:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.PARENT_REPO_TOKEN }}
          ref: Staaging

      - name: Update submodule to latest
        run: |
          git config user.name "github-actions"
          git config user.email "github-actions@github.com"
          git config --global url."https://x-access-token:${{ secrets.PARENT_REPO_TOKEN }}@github.com/".insteadOf "git@github.com:"
          git submodule update --init --remote odoo_sh_dunecrest_crm
          git add odoo_sh_dunecrest_crm
          git diff --cached --quiet || git commit -m "chore: update odoo_sh_dunecrest_crm submodule"
          git push

What each line does:

Line Purpose
repository_dispatch: types: [submodule-updated] Listens for the event sent by the submodule's workflow
token: ${{ secrets.PARENT_REPO_TOKEN }} Checks out the repo with the PAT so git push works (default GITHUB_TOKEN cannot trigger other workflows)
ref: Staaging Checks out the Staaging branch (change this to target a different branch)
git config --global url...insteadOf Rewrites SSH URLs (git@github.com:) to HTTPS with token auth, so the GitHub Actions runner can clone private submodules without SSH keys
git submodule update --init --remote Pulls the latest commit from the submodule's tracked branch (main)
git diff --cached --quiet || git commit Only commits if the submodule pointer actually changed (avoids empty commits)
git push Pushes the updated submodule reference to the parent repo

Important: This workflow file must exist on the main branch (the default branch). GitHub only processes repository_dispatch events from the default branch. The ref: Staaging parameter controls which branch gets checked out and updated -- it does NOT need to match the branch the workflow file lives on.

Commit and push this file to main:

cd odoo_sh_dunecrest  # parent repo root
git checkout main
git add .github/workflows/update-submodule.yml
git commit -m "ci: auto-update submodule on upstream push"
git push origin main

If you are working on a different branch (e.g., Staaging): commit the file there, push, then create a Pull Request from that branch to main and merge it. The workflow will not activate until it exists on main.


Step 6: Verify the Setup

Push an empty test commit to the submodule:

cd odoo_sh_dunecrest_crm
git commit --allow-empty -m "test: trigger auto-update workflow"
git push origin main

Then verify:

  1. Go to github.com/MantleInternational/odoo_sh_dunecrest_crm -> Actions tab
    • You should see a green "Notify Parent Repo" run
  2. Go to github.com/MantleInternational/odoo_sh_dunecrest -> Actions tab
    • You should see a green "Update Submodule" run
  3. Check the Staaging branch commit history -- there should be a new commit: chore: update odoo_sh_dunecrest_crm submodule

For Colleagues Without SSH

If a colleague doesn't have SSH set up, they can use HTTPS for the submodule only (without breaking Odoo.sh which requires SSH on the parent repo):

git config submodule.odoo_sh_dunecrest_crm.url https://github.com/MantleInternational/odoo_sh_dunecrest_crm.git

This only affects the submodule URL locally -- the parent repo's SSH remote stays untouched.


Restricting Auto-Pull to a Specific Branch

By default (without ref), the workflow updates the default branch (main). To target a different branch, add ref: <branch-name> to the checkout step in update-submodule.yml:

- uses: actions/checkout@v4
  with:
    token: ${{ secrets.PARENT_REPO_TOKEN }}
    ref: Staaging # <-- target branch

Updating multiple branches

If you want to update multiple branches (e.g., both main and Staaging), use a matrix strategy:

name: Update Submodule
on:
  repository_dispatch:
    types: [submodule-updated]

jobs:
  update:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        branch: [main, Staaging]
    steps:
      - uses: actions/checkout@v4
        with:
          token: ${{ secrets.PARENT_REPO_TOKEN }}
          ref: ${{ matrix.branch }}

      - name: Update submodule to latest on ${{ matrix.branch }}
        run: |
          git config user.name "github-actions"
          git config user.email "github-actions@github.com"
          git config --global url."https://x-access-token:${{ secrets.PARENT_REPO_TOKEN }}@github.com/".insteadOf "git@github.com:"
          git submodule update --init --remote odoo_sh_dunecrest_crm
          git add odoo_sh_dunecrest_crm
          git diff --cached --quiet || git commit -m "chore: update odoo_sh_dunecrest_crm submodule"
          git push

This runs the update job once per branch listed in the matrix.branch array. Add or remove branches as needed.


Troubleshooting

"Write access to repository not granted" (403)

  • Ensure the PAT has Contents: Read and Write permission for both repositories
  • If using a fine-grained token: ensure both repos are selected under Repository access, and the token is approved at the organization level (org Settings -> Personal access tokens -> approve the token)
  • If using a classic token: ensure it has the repo scope
  • Ensure the token owner has write access to both repositories

Workflow doesn't trigger on parent repo

  • The update-submodule.yml file must exist on the default branch (main). repository_dispatch events only trigger workflows on the default branch.
  • Check that the event_type matches exactly: submodule-updated in both files

Submodule clone fails with SSH errors

  • The git config --global url...insteadOf line rewrites SSH URLs to HTTPS. If it's still failing, verify the PARENT_REPO_TOKEN secret has the correct token value in the parent repo.

Workflow shows "Get started with GitHub Actions" instead of runs

  • The workflow file is not on the main branch yet. Merge it to main first.

Token expired

  • Regenerate the token and update the PARENT_REPO_TOKEN secret in both repos.

Token Maintenance

The PAT expires on the date you set during creation. When it expires:

  1. Go to GitHub -> Settings -> Developer settings -> Personal access tokens -> Fine-grained tokens
  2. Find odoo_sh_dunecrest_crm-auto-update and click Regenerate token
  3. Copy the new token
  4. Update the PARENT_REPO_TOKEN secret in both repos:
    • odoo_sh_dunecrest -> Settings -> Secrets and variables -> Actions -> edit PARENT_REPO_TOKEN
    • odoo_sh_dunecrest_crm -> Settings -> Secrets and variables -> Actions -> edit PARENT_REPO_TOKEN

Adding More Submodules

To add auto-update for another submodule (e.g., odoo_sh_dunecrest_accounting):

  1. Submodule repo: Add a .github/workflows/notify-parent.yml file (same as Step 4, with the PARENT_REPO_TOKEN secret added to the new submodule repo)
  2. Parent repo: Update update-submodule.yml to also update the new submodule:
    git submodule update --init --remote odoo_sh_dunecrest_crm
    git submodule update --init --remote odoo_sh_dunecrest_accounting
    Or use --remote without specifying a name to update all submodules:
    git submodule update --init --remote
  3. PAT: Update the fine-grained token to include the new submodule repo in its Repository access list
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment