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
pushevent - 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
Series: "Automate Your Code with GitHub Actions"
This is part 7 of our series titled "Automate Your Code with GitHub Actions", based on the mini-guide by Bas Steins. Be sure to check out the rest of the series:
- Fundamentals of GitHub Actions
- Events and Triggers in GitHub Actions
- Jobs, Actions, and the Marketplace
- Creating Custom GitHub Actions
- Examples: DevContainers, GitHub Pages, and Cloudflare Workers
- Examples: Data Automation, Linting, and Package Publishing
- Repository Splitting and Quick Reference ← you are here!
Sign up for our newsletter to get notified about the next episode!
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
pushpull_requestscheduleworkflow_dispatchrepository_dispatchissue_commentpull_request_reviewpull_request_review_commentissuesrelease
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!
Join Over 100,000 Developers & Designers
Be the first to know about new content from the Tower blog as well as giveaways and freebies via email.