# Examples This document shows real-world scenarios where `git-auto-commit` is useful, with a working GitHub Actions workflow for each. The scenarios are based on questions and use cases that have come up in the [issues](https://github.com/stefanzweifel/git-auto-commit-action/issues) and [discussions](https://github.com/stefanzweifel/git-auto-commit-action/discussions) of this repository over the years. If you have a use case that isn't covered here, [open a discussion](https://github.com/stefanzweifel/git-auto-commit-action/discussions) — we may add it. ## Table of Contents - [Auto-format code on pull requests](#auto-format-code-on-pull-requests) - [Auto-fix lint errors](#auto-fix-lint-errors) - [Update dependency lock files](#update-dependency-lock-files) - [Build and commit compiled assets](#build-and-commit-compiled-assets) - [Auto-generate API documentation](#auto-generate-api-documentation) - [Update README with generated content](#update-readme-with-generated-content) - [Maintain a CHANGELOG](#maintain-a-changelog) - [Sync translations / i18n files](#sync-translations--i18n-files) - [Publish a static site to a separate branch](#publish-a-static-site-to-a-separate-branch) - [Scheduled data refresh](#scheduled-data-refresh) - [Create a release tag without a commit](#create-a-release-tag-without-a-commit) - [Fail the build instead of pushing changes (drift check)](#fail-the-build-instead-of-pushing-changes-drift-check) - [Sign automated commits with GPG](#sign-automated-commits-with-gpg) - [Squash automated changes into the previous commit](#squash-automated-changes-into-the-previous-commit) --- ## Auto-format code on pull requests **Description:** Run a code formatter (Prettier, php-cs-fixer, Black, gofmt, rustfmt, …) on every pull request and commit the resulting changes back to the contributor's branch. Contributors don't have to think about style; the bot fixes it for them. This is the most common use case for this Action. Running it on `pull_request` means the formatter only touches the PR branch — never your default branch directly. ```yaml name: Format on: pull_request jobs: prettier: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} - uses: actions/setup-node@v4 with: node-version: 20 - run: npx prettier --write . - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "style: apply prettier formatting" ``` > [!TIP] > If the PR comes from a fork, the Action can only push back if the contributor enabled "Allow edits by maintainers". See the [forks section in the README](README.md#use-in-forks-from-public-repositories) for details. --- ## Auto-fix lint errors **Description:** Many linters can both report and auto-fix problems (`eslint --fix`, `rubocop -a`, `ruff --fix`, `stylelint --fix`, …). Use the Action to commit the auto-fixed result so reviewers only see the issues that need human judgement. ```yaml name: Lint and fix on: pull_request jobs: eslint: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} - uses: actions/setup-node@v4 with: node-version: 20 cache: npm - run: npm ci - run: npx eslint . --fix - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "chore: apply eslint --fix" ``` > [!TIP] > `file_pattern` is intentionally omitted here. If one of several custom patterns does not match a file in the repository, `git add` can fail with a pathspec error. Let the linter decide which files to change, or use a custom pattern that you know exists in your repository. --- ## Update dependency lock files **Description:** When a dependency tool produces a fresh lock file (`package-lock.json`, `composer.lock`, `Gemfile.lock`, `poetry.lock`, …), commit only the lock file. Pair this with a scheduled job to keep lock files in sync without manual intervention. ```yaml name: Refresh lock file on: schedule: - cron: "0 6 * * 1" # every Monday at 06:00 UTC workflow_dispatch: jobs: refresh: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm install --package-lock-only - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "chore(deps): refresh package-lock.json" file_pattern: package-lock.json ``` --- ## Build and commit compiled assets **Description:** For projects that ship a `dist/` folder (libraries, browser extensions, themes), build the assets in CI and commit them so consumers can install directly from the repo without a build step. ```yaml name: Build dist on: push: branches: [main] jobs: build: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v4 with: node-version: 20 cache: npm - run: npm ci - run: npm run build - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "build: update dist/" file_pattern: "dist/**" ``` > [!NOTE] > If `dist/` is in `.gitignore`, the Action will not pick up changes. See the [troubleshooting section in the README](README.md#change-to-file-is-not-detected). --- ## Auto-generate API documentation **Description:** Tools like TypeDoc, Doxygen, Sphinx, or `cargo doc` generate documentation from source comments. Regenerate on every push to `main` and commit the output so the published docs always match the latest code. ```yaml name: Docs on: push: branches: [main] jobs: typedoc: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v4 with: node-version: 20 cache: npm - run: npm ci - run: npx typedoc --out docs/api src/index.ts - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "docs: regenerate API reference" file_pattern: "docs/api/**" ``` --- ## Update README with generated content **Description:** Many projects keep dynamic sections in the README — a contributor list, a badge gallery, a table of contents, a list of supported plugins. Regenerate them on a schedule (or when a related file changes) and commit the result. ```yaml name: Update contributors on: schedule: - cron: "0 0 * * 0" # weekly workflow_dispatch: jobs: contributors: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - uses: akhilmhdh/contributors-readme-action@v2.3.10 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "docs: update contributors" file_pattern: README.md ``` --- ## Maintain a CHANGELOG **Description:** Generate or update `CHANGELOG.md` from commit history or release notes after each merge to `main`, and commit it back. ```yaml name: Update CHANGELOG on: push: branches: [main] jobs: changelog: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: fetch-depth: 0 # full history so the generator sees all commits - uses: actions/setup-node@v4 with: node-version: 20 - run: npx conventional-changelog -p angular -i CHANGELOG.md -s - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "docs: update CHANGELOG" file_pattern: CHANGELOG.md ``` --- ## Sync translations / i18n files **Description:** When translations are managed in an external service (Crowdin, Lokalise, Weblate) or extracted from source, pull or generate the latest catalogs on a schedule and commit them. ```yaml name: Sync translations on: schedule: - cron: "0 3 * * *" # daily at 03:00 UTC jobs: sync: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - name: Download translations run: ./scripts/pull-translations.sh env: CROWDIN_TOKEN: ${{ secrets.CROWDIN_TOKEN }} - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "i18n: sync translations from Crowdin" file_pattern: "locales/**/*.json" ``` --- ## Publish a static site to a separate branch **Description:** Build a static site on `main` and push the generated output to a `gh-pages` branch so GitHub Pages can serve it. Use a second checkout directory for the publish branch so the source checkout and generated site do not get mixed together. Create the `gh-pages` branch once before using this workflow. ```yaml name: Build site on: push: branches: [main] jobs: build: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: path: source - uses: actions/checkout@v5 with: ref: gh-pages path: site - name: Build site working-directory: source run: ./build-site.sh # produces output in ./public - name: Replace publish branch contents run: | find site -mindepth 1 -maxdepth 1 ! -name .git -exec rm -rf {} + cp -R source/public/. site/ - uses: stefanzweifel/git-auto-commit-action@v7 with: repository: site branch: gh-pages commit_message: "site: rebuild from ${{ github.sha }}" ``` > [!NOTE] > For most Pages workflows the official [`actions/deploy-pages`](https://github.com/actions/deploy-pages) is a better fit. Use this approach when you specifically want the build output stored in a branch. --- ## Scheduled data refresh **Description:** Pull data from an external source on a schedule and commit it. Common examples: tracking statistics, snapshotting an API response, refreshing a cached dataset. ```yaml name: Refresh stats on: schedule: - cron: "0 * * * *" # hourly workflow_dispatch: jobs: refresh: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - run: curl -sSL https://api.example.com/stats.json -o data/stats.json - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "data: refresh hourly stats" file_pattern: "data/*.json" ``` --- ## Create a release tag without a commit **Description:** Sometimes you want to tag the current HEAD as a release without committing any files. Use `create_git_tag_only` together with `tag_name` and `tagging_message`. ```yaml name: Tag release on: workflow_dispatch: inputs: version: description: "Version to tag (e.g. v1.4.0)" required: true jobs: tag: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 - uses: stefanzweifel/git-auto-commit-action@v7 with: create_git_tag_only: true tag_name: ${{ inputs.version }} tagging_message: "Release ${{ inputs.version }}" ``` --- ## Fail the build instead of pushing changes (drift check) **Description:** Sometimes you don't want a bot to push fixes — you want to fail the build so the contributor fixes them locally. Use the `changes_detected` output as a check: run the formatter, skip branch checkout/fetch/push, and fail if anything changed. ```yaml name: Format check on: pull_request jobs: check: runs-on: ubuntu-latest permissions: contents: read steps: - uses: actions/checkout@v5 - uses: actions/setup-node@v4 with: node-version: 20 - run: npx prettier --write . - uses: stefanzweifel/git-auto-commit-action@v7 id: auto-commit with: skip_checkout: true skip_fetch: true skip_push: true - name: Fail if formatting was needed if: steps.auto-commit.outputs.changes_detected == 'true' run: | echo "::error::Code is not formatted. Run 'npx prettier --write .' locally." exit 1 ``` --- ## Sign automated commits with GPG **Description:** If your branch protection rules require signed commits, the bot's commits need to be signed too. Import a GPG key first, then tell the Action to use the key's identity as the commit author. ```yaml name: Format (signed) on: pull_request jobs: format: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} - name: Import GPG key id: import-gpg uses: crazy-max/ghaction-import-gpg@v6 with: gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PASSPHRASE }} git_user_signingkey: true git_commit_gpgsign: true - run: npx prettier --write . - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: "style: apply prettier" commit_user_name: ${{ steps.import-gpg.outputs.name }} commit_user_email: ${{ steps.import-gpg.outputs.email }} commit_author: "${{ steps.import-gpg.outputs.name }} <${{ steps.import-gpg.outputs.email }}>" ``` See discussion [#334](https://github.com/stefanzweifel/git-auto-commit-action/discussions/334) for background. --- ## Squash automated changes into the previous commit **Description:** Avoid noisy "apply automatic changes" commits by amending the last commit instead. Useful when the bot fix is trivial and you don't want a separate entry in the history. > [!CAUTION] > Amending rewrites history. Only use this on branches where force-pushing is acceptable (typically PR branches, never `main`). ```yaml name: Format (amend) on: pull_request jobs: format: runs-on: ubuntu-latest permissions: contents: write steps: - uses: actions/checkout@v5 with: ref: ${{ github.head_ref }} fetch-depth: 2 # need previous commit for --amend - run: npx prettier --write . - name: Read previous commit metadata id: last run: | echo "message=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT echo "author=$(git log -1 --pretty='%an <%ae>')" >> $GITHUB_OUTPUT - uses: stefanzweifel/git-auto-commit-action@v7 with: commit_message: ${{ steps.last.outputs.message }} commit_author: ${{ steps.last.outputs.author }} commit_options: "--amend --no-edit" push_options: "--force" skip_fetch: true ``` See discussion [#159](https://github.com/stefanzweifel/git-auto-commit-action/issues/159#issuecomment-845347950) for details.