Skip to main content
< Back to Blog

Automate Your Code with GitHub Actions #7: Repository Splitting and Quick Reference

In this final article of our series, we tackle one more advanced real-world recipe — repository splitting — and then wrap up with a comprehensive quick reference that you can bookmark and revisit whenever you need to look up a context, event, or workflow syntax detail.

Who is Bas Steins?

Bas is a software developer and technology trainer based in the triangle between the Netherlands, Germany, and Belgium. For almost two decades, he has been helping people turn their ideas into software and helping other developers write better code. This series is based on his mini-guide "Automate Your Code with GitHub Actions".

Repository Split

This example demonstrates how to use a GitHub Action to split a repository into multiple repositories based on a specific path. This can be useful when you want to separate different parts of a project into their own repositories while maintaining a single source of truth.

For example, if you maintain a monolithic repository of a closed source project and want to open source a specific part of it, you can use this workflow to automatically split the open source part into a separate repository.

What you'll learn

  • Using a GitHub Action on the push event
  • Publishing content from a repository to another repository
name: 'Repository Split'

on:
  push:
    branches:
      - main
    paths:
      - 'scripts/**'

run-name: >-
  Repository Split

concurrency:
  group: 'scripts'
  cancel-in-progress: false

jobs:
  filter:
    name: 'Publish Script(s)'
    runs-on: ubuntu-latest
    env:
      commit_author_name: 'github-actions[bot]'
      commit_author_email: 'github-actions[bot]@users.noreply.github.com'
      origin: sebst/thatus-wi-2024-mono
      ref: main
      paths: '("scripts/")'
      path_globs: '()'
      rename: '("scripts/.github/:.github/")'
      target: sebst/thatus-wi-2024-split
      PAT_GITHUB_TOKEN: ${{ secrets.PAT_GITHUB_TOKEN }}
    permissions:
      contents: write
    steps:
    - uses: actions/checkout@v4
      with:
        # Relative path under $GITHUB_WORKSPACE to place the repository
        path: 'origin'
        repository: '${{ env.origin }}'
        ref: ${{ env.ref }}
        # fetch all commits
        fetch-depth: 0
        fetch-tags: false
        # use default token or i.e. ${secrets.PERSONAL_ACCESS_TOKEN}
        token: ${{ secrets.PAT_GITHUB_TOKEN }}
        persist-credentials: false
        # alternative: SSH key
        # ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
    - uses: actions/checkout@v4
      with:
        path: 'target'
        repository: '${{ env.target }}'
        token: ${{ secrets.PAT_GITHUB_TOKEN }}
        # fetch all commits
        fetch-depth: 0
        fetch-tags: false
        persist-credentials: false

    - name: Split Repo
      working-directory: .
      run: |
        # [Script]

        echo '::group::Install "git-filter-repo"'
        sudo apt-get update
        sudo apt-get install -y \
          git-filter-repo
        echo '::endgroup::'

        echo '::group::Versions(s)'
        git --version
        git-filter-repo --version
        echo '::endgroup::'

        echo '::group::Git Config'
        git config --global user.name ${{ env.commit_author_name }} || echo user.name failed
        git config --global user.email ${{ env.commit_author_email }} || echo user.mail failed
        git config --global --unset credential.helper || echo credential.helper failed
        git -C ./origin config --unset credential.helper || echo origin local credential.helper failed
        git -C ./target config --unset credential.helper || echo target local credential.helper failed
        echo '::endgroup::'

        echo '::group::Git Remote(s) [Before]'
        git -C ./origin remote -v || echo origin remote -v failed
        git -C ./target remote -v || echo target remote -v failed
        echo '::endgroup::'

        echo '::group::Extract "--path [..]" Parameters from Inputs'
        declare -ra pathsArray=${{ env.paths }}
        declare -a pathArguments=()
        for relativePath in ${pathsArray[@]}; do
          pathArguments+=( "--path" "${relativePath}" )
        done
        echo '::endgroup::'

        echo '::group::Extract "--path-glob [..]" Parameters from Inputs'
        declare -ra pathGlobsArray=${{ env.path_globs }}
        declare -a pathGlobArguments=()
        for pathGlob in ${pathGlobsArray[@]}; do
          pathGlobArguments+=( "--path" "${pathGlob}" )
        done
        echo '::endgroup::'

        echo '::group::Extract "--path-rename [..]" Parameters from Inputs'
        declare -ra renameArray=${{ env.rename }}
        declare -a pathRenameArguments=()
        for rename in ${renameArray[@]}; do
          pathRenameArguments+=( "--path-rename" "${rename}" )
        done
        echo '::endgroup::'

        echo '::group::debug: "--path(-*) [..]" Parameters'
        echo "# of Path Arguments: ${#pathArguments[@]}"
        printf '%s\n' "${pathArguments[@]}"
        echo "# of Path Glob Arguments: ${#pathGlobArguments[@]}"
        printf '%s\n' "${pathGlobArguments[@]}"
        echo "# of Path Rename Arguments: ${#pathRenameArguments[@]}"
        printf '%s\n' "${pathRenameArguments[@]}"
        echo '::endgroup::'

        # see: https://htmlpreview.github.io/?https://github.com/newren/git-filter-repo/blob/docs/html/git-filter-repo.html
        echo '::group::Run "git-filter-repo"'
        git filter-repo \
          --refs ${{ env.ref }} \
          "${pathArguments[@]}" \
          "${pathGlobArguments[@]}" \
          "${pathRenameArguments[@]}" \
          --name-callback \
            'return b"${{ env.commit_author_name }}"' \
          --email-callback \
            'return b"${{ env.commit_author_email }}"' \
          --commit-callback \
            'commit.message += f"\noriginal-commit: https://github.com/${{ env.origin }}/commit/{commit.original_id.decode()}/".encode("ascii")' \
          --source ./origin \
          --target ./target
        echo '::endgroup::'

        echo '::group::Git Branch'
        git -C ./target branch -va
        echo '::endgroup::'

        echo '::group::Git Log'
        git -C ./target log --oneline
        echo '::endgroup::'

        echo '::group::Git Remote(s) [After]'
        git -C ./origin remote -v || echo origin remote -v failed
        git -C ./target remote -v || echo target remote -v failed
        echo '::endgroup::'

        echo '::group::Fix "could not read Username for https://github.com: No such device or address"'
        git config --global url.https://${{ secrets.PAT_GITHUB_TOKEN }}@github.com/.insteadOf https://github.com/
        echo '::endgroup::'
    - name: Push changes
      uses: ad-m/github-push-action@master
      with:
        directory: 'target'
        repository: ${{ env.target }}
        branch: ${{ env.ref }}
        tags: false
        force: false
        force_with_lease: true
        PAT_GITHUB_TOKEN: ${{ secrets.PAT_GITHUB_TOKEN }}
        ssh: false

Quick Reference

Anatomy of a Workflow

name: 'Hello World Workflow'
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
    - name: 'Checkout code'
      uses: actions/checkout@v4

    - name: 'Run Hello World Action'
      uses: ./ # Reference the action in the current repository

Frequently Used Events

  • push
  • pull_request
  • schedule
  • workflow_dispatch
  • repository_dispatch
  • issue_comment
  • pull_request_review
  • pull_request_review_comment
  • issues
  • release

Log Groups

  • echo "::group::Collapsible Group"
  • echo "::endgroup::"

Context Reference

☝️ The following tables are taken from the GitHub Actions documentation.

github

Property name Description
github The top-level context available during any job or step in a workflow. This object contains all the properties listed below.
github.action The name of the action currently running, or the id of a step. GitHub removes special characters, and uses the name __run when the current step runs a script without an id. If you use the same action more than once in the same job, the name will include a suffix with the sequence number with an underscore before it.
github.action_path The path where an action is located. This property is only supported in composite actions. You can use this path to access files located in the same repository as the action.
github.action_ref For a step executing an action, this is the ref of the action being executed. For example, v2.
github.action_repository For a step executing an action, this is the owner and repository name of the action. For example, actions/checkout.
github.action_status For a composite action, the current result of the composite action.
github.actor The username of the user that triggered the initial workflow run. If the workflow run is a re-run, this value may differ from github.triggering_actor.
github.actor_id The account ID of the person or app that triggered the initial workflow run. For example, 1234567.
github.api_url The URL of the GitHub REST API.
github.base_ref The base_ref or target branch of the pull request in a workflow run. This property is only available when the event that triggers a workflow run is either pull_request or pull_request_target.
github.env Path on the runner to the file that sets environment variables from workflow commands.
github.event The full event webhook payload. You can access individual properties of the event using this context.
github.event_name The name of the event that triggered the workflow run.
github.event_path The path to the file on the runner that contains the full event webhook payload.
github.graphql_url The URL of the GitHub GraphQL API.
github.head_ref The head_ref or source branch of the pull request in a workflow run.
github.job The job_id of the current job.
github.path Path on the runner to the file that sets system PATH variables from workflow commands.
github.ref The fully-formed ref of the branch or tag that triggered the workflow run.
github.ref_name The short ref name of the branch or tag that triggered the workflow run.
github.ref_protected true if branch protections or rulesets are configured for the ref that triggered the workflow run.
github.ref_type The type of ref that triggered the workflow run. Valid values are branch or tag.
github.repository The owner and repository name. For example, octocat/Hello-World.
github.repository_id The ID of the repository. For example, 123456789.
github.repository_owner The repository owner's username. For example, octocat.
github.repository_owner_id The repository owner's account ID. For example, 1234567.
github.repositoryUrl The Git URL to the repository. For example, git://github.com/octocat/hello-world.git.
github.retention_days The number of days that workflow run logs and artifacts are kept.
github.run_id A unique number for each workflow run within a repository.
github.run_number A unique number for each run of a particular workflow in a repository.
github.run_attempt A unique number for each attempt of a particular workflow run in a repository.
github.secret_source The source of a secret used in a workflow. Possible values are None, Actions, Codespaces, or Dependabot.
github.server_url The URL of the GitHub server. For example: https://github.com.
github.sha The commit SHA that triggered the workflow.
github.token A token to authenticate on behalf of the GitHub App installed on your repository.
github.triggering_actor The username of the user that initiated the workflow run.
github.workflow The name of the workflow.
github.workflow_ref The ref path to the workflow. For example, octocat/hello-world/.github/workflows/my-workflow.yml@refs/heads/my_branch.
github.workflow_sha The commit SHA for the workflow file.
github.workspace The default working directory on the runner for steps, and the default location of your repository when using the checkout action.

env

Property name Description
env This context changes for each step in a job. You can access this context from any step in a job. This object contains the properties listed below.
env.<env_name> The value of a specific environment variable.

job

Property name Description
job This context changes for each job in a workflow run. You can access this context from any step in a job. This object contains all the properties listed below.
job.container Information about the job's container.
job.container.id The ID of the container.
job.container.network The ID of the container network. The runner creates the network used by all containers in a job.
job.services The service containers created for a job.
job.services.<service_id>.id The ID of the service container.
job.services.<service_id>.network The ID of the service container network. The runner creates the network used by all containers in a job.
job.services.<service_id>.ports The exposed ports of the service container.
job.status The current status of the job. Possible values are success, failure, or cancelled.

jobs

Property name Description
jobs This is only available in reusable workflows, and can only be used to set outputs for a reusable workflow. This object contains all the properties listed below.
jobs.<job_id>.result The result of a job in the reusable workflow. Possible values are success, failure, cancelled, or skipped.
jobs.<job_id>.outputs The set of outputs of a job in a reusable workflow.
jobs.<job_id>.outputs.<output_name> The value of a specific output for a job in a reusable workflow.

steps

Property name Description
steps This context changes for each step in a job. You can access this context from any step in a job. This object contains all the properties listed below.
steps.<step_id>.outputs The set of outputs defined for the step.
steps.<step_id>.conclusion The result of a completed step after continue-on-error is applied. Possible values are success, failure, cancelled, or skipped. When a continue-on-error step fails, the outcome is failure, but the final conclusion is success.
steps.<step_id>.outcome The result of a completed step before continue-on-error is applied. Possible values are success, failure, cancelled, or skipped. When a continue-on-error step fails, the outcome is failure, but the final conclusion is success.
steps.<step_id>.outputs.<output_name> The value of a specific output.

runner

Property name Description
runner This context changes for each job in a workflow run. This object contains all the properties listed below.
runner.name The name of the runner executing the job. This name may not be unique in a workflow run as runners at the repository and organization levels could use the same name.
runner.os The operating system of the runner executing the job. Possible values are Linux, Windows, or macOS.
runner.arch The architecture of the runner executing the job. Possible values are X86, X64, ARM, or ARM64.
runner.temp The path to a temporary directory on the runner. This directory is emptied at the beginning and end of each job.
runner.tool_cache The path to the directory containing preinstalled tools for GitHub-hosted runners.
runner.debug This is set only if debug logging is enabled, and always has the value of 1. It can be useful as an indicator to enable additional debugging or verbose logging in your own job steps.
runner.environment The environment of the runner executing the job. Possible values are: github-hosted for GitHub-hosted runners provided by GitHub, and self-hosted for self-hosted runners configured by the repository owner.

secrets

Property name Description
secrets This context is the same for each job in a workflow run. You can access this context from any step in a job. This object contains all the properties listed below.
secrets.GITHUB_TOKEN Automatically created token for each workflow run.
secrets.<secret_name> The value of a specific secret.

☝️ Secrets starting with GITHUB_ are reserved for GitHub Actions and cannot be used as custom secrets. For example, GITHUB_TOKEN is a reserved secret that is automatically created for each workflow run. You cannot create a custom secret with the name GITHUB_TOKEN.

strategy

Property name Description
strategy This context changes for each job in a workflow run. You can access this context from any job or step in a workflow. This object contains all the properties listed below.
strategy.fail-fast When this evaluates to true, all in-progress jobs are canceled if any job in a matrix fails.
strategy.job-index The index of the current job in the matrix. Note: This number is a zero-based number. The first job's index in the matrix is 0.
strategy.job-total The total number of jobs in the matrix. Note: This number is not a zero-based number. For example, for a matrix with four jobs, the value of job-total is 4.
strategy.max-parallel The maximum number of jobs that can run simultaneously when using a matrix job strategy.

matrix

Property name Description
matrix This context is only available for jobs in a matrix and changes for each job in a workflow run. You can access this context from any job or step in a workflow. This object contains the properties listed below.
matrix.<property_name> The value of a matrix property.

needs

Property name Description
needs This context is only populated for workflow runs that have dependent jobs and changes for each job in a workflow run. You can access this context from any job or step in a workflow. This object contains all the properties listed below.
needs.<job_id> A single job that the current job depends on.
needs.<job_id>.outputs The set of outputs of a job that the current job depends on.
needs.<job_id>.outputs.<output_name> The value of a specific output for a job that the current job depends on.
needs.<job_id>.result The result of a job that the current job depends on. Possible values are success, failure, cancelled, or skipped.

inputs

Property name Description
inputs This context is only available in a reusable workflow or in a workflow triggered by the workflow_dispatch event. You can access this context from any job or step in a workflow. This object contains the properties listed below.
inputs.<name> Each input value passed from an external workflow. Possible types: string, number, boolean, or choice.

We hope you enjoyed our comprehensive guide on GitHub Actions. By now, you should have a complete understanding of how complex tasks can be automated using this powerful tool.

For more tips, tutorials, and guides, be sure to sign up for our newsletter below and follow Tower on Twitter and LinkedIn!

Your Download is in Progress…

Giveaways. Cheat Sheets. eBooks. Discounts. And great content from our blog!