I'm building Docker images with Github Actions and want to tag images with the branch name.
I found the GITHUB_REF
variable, but it results in refs/heads/feature-branch-1
and I need only feature-branch-1
.
I'm building Docker images with Github Actions and want to tag images with the branch name.
I found the GITHUB_REF
variable, but it results in refs/heads/feature-branch-1
and I need only feature-branch-1
.
I added a separate step for extracting branch name from $GITHUB_HEAD_REF
/$GITHUB_REF
¹ (pr and push) and set it to the step output:
- name: Extract branch name
shell: bash
run: echo "branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}" >> $GITHUB_OUTPUT
id: extract_branch
after that, I can use it in the next steps with steps.<step_id>.outputs.branch
:
- name: Push to ECR
id: ecr
uses: jwalton/gh-ecr-push@master
with:
access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
region: us-west-2
image: eng:${{ steps.extract_branch.outputs.branch }}
¹ $GITHUB_HEAD_REF
on pull_request
(pr) and $GITHUB_REF
on push
. Description:
Variable | Description |
---|---|
GITHUB_HEAD_REF |
The head ref or source branch of the pull request in a workflow run. This property is only set when the event that triggers a workflow run is either pull_request or pull_request_target . For example, feature-branch-1 . (source) |
GITHUB_REF |
The fully-formed ref of the branch or tag that triggered the workflow run. For workflows triggered by push , this is the branch or tag ref that was pushed. For workflows triggered by pull_request , this is the pull request merge branch. For workflows triggered by release , this is the release tag created. For other triggers, this is the branch or tag ref that triggered the workflow run. This is only set if a branch or tag is available for the event type. The ref given is fully-formed, meaning that for branches the format is refs/heads/<branch_name> , for pull requests it is refs/pull/<pr_number>/merge , and for tags it is refs/tags/<tag_name> . For example, refs/heads/feature-branch-1 . (source) |
Full description of these and all other Default environment variables - Learn Gihtub Actions (archived copy).
Looking for the Microsoft Github Action Context named github
? See the answer by ysfaran and/or the answer by Dusan Plavak.
I believe GITHUB_REF
is the only environment variable that includes the branch name.
If your branch name does not contain a /
in it (for example deploy/abc
), then you can extract just the branch name from the rest of that string like this:
${GITHUB_REF##*/}
Example:
$ GITHUB_REF=refs/heads/feature-branch-1
$ echo ${GITHUB_REF##*/}
feature-branch-1
Update: Added a complete workflow example.
name: CI
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v1
- name: Branch name
run: echo running on branch ${GITHUB_REF##*/}
- name: Build
run: docker build -t tedmiston/tag-example:${GITHUB_REF##*/} .
Source: https://github.com/tedmiston/x/blob/master/.github/workflows/workflow.yml
Run docker build -t tedmiston/tag-example:${GITHUB_REF##*/} .
docker build -t tedmiston/tag-example:${GITHUB_REF##*/} .
shell: /bin/bash -e {0}
Sending build context to Docker daemon 146.9kB
Step 1/1 : FROM alpine
latest: Pulling from library/alpine
9d48c3bd43c5: Pulling fs layer
9d48c3bd43c5: Verifying Checksum
9d48c3bd43c5: Download complete
9d48c3bd43c5: Pull complete
Digest: sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb
Status: Downloaded newer image for alpine:latest
---> 961769676411
Successfully built 961769676411
Successfully tagged tedmiston/tag-example:master
Log: https://github.com/tedmiston/x/commit/cdcc58a908e41d3d90c39ab3bf6fef1ad2c4238a/checks#step:4:16
Run docker build -t tedmiston/tag-example:${GITHUB_REF##*/} .
docker build -t tedmiston/tag-example:${GITHUB_REF##*/} .
shell: /bin/bash -e {0}
Sending build context to Docker daemon 144.9kB
Step 1/1 : FROM alpine
latest: Pulling from library/alpine
9d48c3bd43c5: Pulling fs layer
9d48c3bd43c5: Verifying Checksum
9d48c3bd43c5: Download complete
9d48c3bd43c5: Pull complete
Digest: sha256:72c42ed48c3a2db31b7dafe17d275b634664a708d901ec9fd57b1529280f01fb
Status: Downloaded newer image for alpine:latest
---> 961769676411
Successfully built 961769676411
Successfully tagged tedmiston/tag-example:branch-name-test
Log: https://github.com/tedmiston/x/commit/4e8d31259f861aaa2c30375756fc081c3659bddf/checks#step:4:16
See this answer for more on parameter expansion syntax.
For reference the page Virtual environments for GitHub Actions lists all of the environment variables available in the execution environment.
Be aware that if you are executing your GitHub action on pull request trigger, then GITHUB_REF
variable will contain something like refs/pull/421/merge
so if you will try to git push
to that name it will most likely fail.
What you can use though are references on the GitHub context in your YAML. Something like: ${{ github.head_ref }}
This works for every trigger that you can specify under on
(e.g push
or pull_request
):
env:
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
The trick is that github.head_ref
is only set when the workflow was triggered by a pull_request
and it contains the value of the source branch of the PR. github.ref_name
will than only be used if the workflow was not triggered by a pull_request
and it also just contains the branch name.
Detailed explanation from official GitHub docs:
github.ref_name
string
The short ref name of the branch or tag that triggered the workflow run. This value matches the branch or tag name shown on GitHub. For example, feature-branch-1.
github.head_ref
string
The head_ref or source 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.
Update
GitHub now supports the GITHUB_REF_NAME
, which stands for: The branch or tag name that triggered the workflow run
.
GitHub docs on this https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
Using setenv
is now deprecated. It is advised to use environment files. Building on @youjin's answer, while still allowing feature/
branches (replacing all occurences of /
with -
), I am now using this:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Get branch name (merge)
if: github.event_name != 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_REF#refs/heads/} | tr / -)" >> $GITHUB_ENV
- name: Get branch name (pull request)
if: github.event_name == 'pull_request'
shell: bash
run: echo "BRANCH_NAME=$(echo ${GITHUB_HEAD_REF} | tr / -)" >> $GITHUB_ENV
- name: Debug
run: echo ${{ env.BRANCH_NAME }}
You could use https://github.com/rlespinasse/github-slug-action
# Just add this =>
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@v3.x
# And you get this =>
- name: Print slug/short variables
run: |
echo "Slug variables"
echo " - ${{ env.GITHUB_REF_SLUG }}"
echo " - ${{ env.GITHUB_HEAD_REF_SLUG }}"
echo " - ${{ env.GITHUB_BASE_REF_SLUG }}"
echo " - ${{ env.GITHUB_REPOSITORY_SLUG }}"
# output e.g. : master feat-new-feature v1.0.0 product-1.0.0-rc.2 new-awesome-product
echo "Slug URL variables"
echo " - ${{ env.GITHUB_REF_SLUG_URL }}"
echo " - ${{ env.GITHUB_HEAD_REF_SLUG_URL }}"
echo " - ${{ env.GITHUB_BASE_REF_SLUG_URL }}"
echo " - ${{ env.GITHUB_REPOSITORY_SLUG_URL }}"
# output e.g. : master feat-new-feature v1-0-0 product-1-0-0-rc-2 new-awesome-product
echo "Short SHA variables"
echo " - ${{ env.GITHUB_SHA_SHORT }}"
# output e.g. : ffac537e
For those just finding this thread, you can now use GITHUB_REF_NAME
e.g. ${{ github.ref_name }}
. https://docs.github.com/en/actions/learn-github-actions/environment-variables#default-environment-variables
So if your triggered action workflow branch is main
this variable will be set to main
. This is useful if you have multiple repos with release
and main
branches, for instance.
How to get the current branch within Github Actions?
Assuming ${{ github.ref }}
is something like refs/heads/mybranch
, you can extract the branch name using the following method:
steps:
- name: Prints the current branch name
run: echo "${GITHUB_BRANCH##*/}"
env:
GITHUB_BRANCH: ${{ github.ref }}
If your branch includes slashes (such as feature/foo
), use the following syntax:
steps:
- name: Prints the current branch name
run: echo "${GITHUB_REF#refs/heads/}"
Credits: @rmunn comment
Or use the method from the accepted answer, here is much shorter version (lint friendly):
steps:
- name: Get the current branch name
shell: bash
run: echo "::set-output name=branch::${GITHUB_REF#refs/heads/}"
id: myref
Then refer in other steps as ${{ steps.myref.outputs.branch }}
.
Notes:
The GitHub Action FranzDiebold/github-env-vars-action exposes several useful environment variables, such as current branch name and their slug values. I made this action exactly for this use case.
steps:
- uses: FranzDiebold/github-env-vars-action@v1.2.0
- name: Print environment variables
run: |
echo "GITHUB_REPOSITORY_SLUG=$GITHUB_REPOSITORY_SLUG"
echo "GITHUB_REPOSITORY_OWNER=$GITHUB_REPOSITORY_OWNER"
echo "GITHUB_REPOSITORY_OWNER_SLUG=$GITHUB_REPOSITORY_OWNER_SLUG"
echo "GITHUB_REPOSITORY_NAME=$GITHUB_REPOSITORY_NAME"
echo "GITHUB_REPOSITORY_NAME_SLUG=$GITHUB_REPOSITORY_NAME_SLUG"
echo "GITHUB_REF_SLUG=$GITHUB_REF_SLUG"
echo "GITHUB_REF_NAME=$GITHUB_REF_NAME"
echo "GITHUB_REF_NAME_SLUG=$GITHUB_REF_NAME_SLUG"
echo "GITHUB_SHA_SHORT=$GITHUB_SHA_SHORT"
A demo for all Operating systems (Linux, macOS and Windows) is also available in the demo workflows file of the repository!
To set it as an environment variable, I use this syntax:
- name: Extract branch name
shell: bash
run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_REF#refs/heads/} | sed 's/\//_/g')"
- name: Test
run: echo "${BRANCH_NAME}"
I found this syntax here: Github actions - starter worflows#How to define env variable? #68
Rmq: the sed 's/\//_/g'
is to replace /
by _
in the branch name
Heres a complete workflow that works for both push
and pull_request
events
name: whichBranch
on: [pull_request, push]
jobs:
which_branch:
runs-on: ubuntu-latest
steps:
- name: Extract branch name on push
if: github.event_name != 'pull_request'
shell: bash
run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_REF#refs/heads/})"
id: extract_branch
- name: Extract branch name on pull request
if: github.event_name == 'pull_request'
run: echo "::set-env name=BRANCH_NAME::$(echo ${GITHUB_HEAD_REF})"
- name: Print branch name
run: echo 'The branch name is' $BRANCH_NAME
I just made a simple test within GitHub Actions using a bash script:
#!/bin/bash
echo Reserved for REPO_NAME=${GITHUB_REPOSITORY##*/}
echo GITHUB_REF=${GITHUB_REF}
echo EXTRACT_GITHUB_REF=${GITHUB_REF##*/}
echo EXTRACT_GITHUB_REF_HEADS=$(echo ${GITHUB_REF#refs/heads/})
cd $REPO_NAME
git checkout ${GITHUB_REF##*/}
git checkout $(echo ${GITHUB_REF#refs/heads/})
Here is screenshot of the output:
So both
${GITHUB_REF##*/}
and $(echo ${GITHUB_REF#refs/heads/})
are correct
If you're using V2 of actions/checkout
then you can always just run git branch --show-current
to just get the name of the branch currently checked out.
Now ${{github.ref}}
is the correct way to get branch name.
Please remember ${{github.ref}}
has refs/heads/..
prefix
Solution to deal with both pull_request
and push
events. Implements the workaround to save obtained branch name for further steps, since set-env
is deprecated.
Doesn't require third-party actions.
name: CI
on: [ pull_request, push ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: "Get branch name and save to env"
env:
IS_PR: ${{ github.EVENT_NAME == 'pull_request' }}
run: |
if ${IS_PR}; then
BRANCH_NAME="${GITHUB_HEAD_REF}"
else
BRANCH_NAME="${GITHUB_REF##*/}"
fi
echo "BRANCH_NAME=${BRANCH_NAME}" >> $GITHUB_ENV
- name: "Another step uses branch name"
run: echo "Branch name is ${{ env.BRANCH_NAME }}"
To also deal with the pull_request
event (in which case the $GITHUB_REF
contains something not useful like refs/pull/519/merge
) you can use this one liner:
- name: Set branch name
run: echo "::set-output name=branch_name::$(echo ${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}})"
Use branch name on GitHub actions
Convenience action for using current branch name. Usage
name: build
on: push
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- run: npm ci
- uses: nelonoel/branch-name@v1
# Use branch name for whatever purpose
- run: echo ${BRANCH_NAME}
For people using Windows image to run actions, a few key points to know about:
- run: |
...
shell: cmd
So, all in all, you don't need to waste potentially hours trying to figure out how to do things in dilapidated cmd way (like I did).
And for the simple purpose of getting the name of the current branch, you can either use the popular solutions while setting the shell to 'bash', or use for example the following simple way to set a variable in the default PowerShell shell:
$branchName = $Env:GITHUB_REF -replace "refs/heads/", ""
I made an action that gets the branch name regardless of pull_request trigger or not. https://github.com/EthanSK/git-branch-name-action
There's a very simple git command to get the current branch:
git rev-parse --abbrev-ref HEAD
To get the output in an env file variable simply put:
- name: Set CURRENT_BRANCH run: echo "CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV
To get the output from the env variable:
- name: Get CURRENT_BRANCH run: echo ${{ env.CURRENT_BRANCH}}
Source: https://www.techiedelight.com/determine-current-branch-name-git/
Just repeating here for better visibility what others have written as simple comments in previous replies:
https://docs.github.com/en/actions/learn-github-actions/environment-variables
The branch name for pull requests only is exposed in this environment variable:
GITHUB_HEAD_REF Only set for pull request events. The name of the head branch.
In GitHub actions, the corresponding context key is:
github.head_ref
if: github.ref == 'refs/heads/integration' && github.event_name == 'push'
You can use the above command and replace whatever branch or event you want to run for.
Running on Windows?. Windows default command is a PowerShell terminal.
- name: SET CURRENT_BRANCH
run: |
$branchName = "${{github.ref}}".Split("/")["${{github.ref}}".Split("/").Length -1]
echo "::set-env name=CURRENT_BRANCH::$(echo $branchName)"
Here's a snippet which set's an environment variable based on $GITHUB_REF
, which defaults to dev
if not present.
Adjust the sed command as per your requirements.
export GIT_BRANCH=$(echo ${GITHUB_REF:-dev} | sed s/.*\\///g)
Normally, I always have a script written in either nodejs
or python
, which gets invoked from the workflow.yaml
. The script normally takes care of works like getting proper branch reference.
I have a function like below, in a prepare-deployment.js
script-
const VALID_REF_PREFIX = 'refs/heads/';
...
function getBranchRef(isProd = false) {
let branchRef = 'origin/master';
if (isProd) {
return branchRef;
}
/**
* When the workflow is invoked from manual flow, the branch name
* is in GITHUB_REF, otherwise, we have to look into GITHUB_BASE_REF
*/
if (GITHUB_REF.startsWith(VALID_REF_PREFIX)) {
// coming from a manual workflow trigger
branchName = `origin/${GITHUB_REF.replace(VALID_REF_PREFIX, '')}`;
} else {
// coming from a PR
branchRef = `origin/${GITHUB_HEAD_REF}`;
}
return branchRef;
}
This takes care of the following scenarios-
We currently have a separate job, that runs before all other jobs. That step determines in what environment it runs, based on the branch name. Our branches are associated with specific environments to deploy infrastructure and code bases. Each environment also has its own secrets (github enterprise feature).
The output environment variable can be used in all other consecutive jobs. You can use that variable within a step, to set it as NODE_ENV
for example, or tag a docker image with it. You could also set a concurrency on that specific variable to ensure that only a single job or workflow using the same value will run at a time. This makes it very powerful.
Below is an example of what I described above:
name: Build pipeline
on:
push:
branches:
- feature/*
- develop
- release/*
- main
jobs:
environments:
name: Set environment
runs-on: ubuntu-latest
steps:
- run: echo "Setting $ENVIRONMENT.."
outputs:
# Defaults to 'dev' in case of a feature branch
# You could also use the contains expression if needed
environment: ${{ github.ref == 'refs/heads/main' && 'prd' || (startsWith(github.ref, 'refs/heads/release/') && 'acc' || github.ref == 'refs/heads/develop' && 'tst' || 'dev') }}
build:
name: Docker build
runs-on: ubuntu-latest
needs: [environments]
environment: ${{ needs.environments.outputs.environment }} # Enterprise only
concurrency: ${{ needs.environments.outputs.environment }}
env:
ENVIRONMENT: ${{ needs.environments.outputs.environment }}
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build
run: |
docker build . \
-t hello/world:${{ needs.environments.outputs.environment }}
Note: because extracting the environment name is not done in bash or powershell, you are bound to the limited expressions github actions offers. If you need more fancy stuff you could do it differently, there is no single truth. However, I always like to keep things simple and readable.
Alternative (quick) option
If you don't mind using other people's github actions, you could use one of the many actions from the marketplace that do a find a replace. An example can be found here, that looks like:
on: [push]
jobs:
replace-job:
runs-on: ubuntu-latest
name: 'Find and replace'
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Remove refs/heads/ from string
uses: mad9000/actions-find-and-replace-string@1
id: findandreplace
with:
source: ${{ github.ref }}
find: 'refs/heads/'
replace: ''
- name: Branch name
run: echo "The branch name is ${{ steps.findandreplace.outputs.value }}"
To get the ref name on a delete event I ended up using sed
.
on:
delete:
...
steps:
- name: Do something
shell: bash
run: |
refname=$(sed -e s:refs/heads/::g -e s:/:-:g <<< ${{ github.event.ref }})
cut refs/heads/ and convert slashes to dashes, .e.g. refs/heads/feature/somefeature
to feature-somefeature
I have had to do this several different times for events that run on the PR sync event and then on push to main (e.g. building tagged container images) and I don't particularly like:
/
separated branches, e.g. fix/123
.I thought I would add a small bash
snippet that will work on push and pull_request events since I didn't see one here:
echo "${GITHUB_REF_NAME}" | grep -P '[0-9]+/merge' &> /dev/null && export ref="${GITHUB_HEAD_REF}" || export ref="${GITHUB_REF_NAME}"
The $ref
variable will hold the branch name on push and pull_request events and will handle gitflow/style/branches
.
This works on the assumption that GH actions creates a (typically unexpected) {pr number}/merge
branch for actions that run on PR sync, the grep
call will only return 0
when the branch name matches the (Perl-style) regex and follow the &&
path to export ref
as the value of GITHUB_HEAD_REF
. Or, for branches that don't match the regex (like main
).
The output redirect on grep
just prevents the case of a regex match printing to stdout.
Naturally, this won't work if you need the push event on a branch that matches the regex.
It's simple to get the current branch and the below code works if the event was triggered by a push event.
github.ref_name
is a predefined variable to get the branch name.
jobs:
main-branch-build:
if: github.ref_name == 'main'
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
feature-branch-build:
if: github.ref_name != 'main'
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
Use $GITHUB_REF_NAME
Documentation: https://docs.github.com/en/actions/learn-github-actions/variables
This works locally (using git
, not the Github action environment variables) and in Github actions in its reincarnations pull request, push and merge:
#!/bin/bash
echo "${GITHUB_HEAD_REF:-$(git branch --show-current)}"
In a Github action:
- run: echo "${GITHUB_HEAD_REF:-$(git branch --show-current)}" >> $GITHUB_OUTPUT
shell: bash
id: branch