{"id":15673874,"url":"https://github.com/karlhorky/github-tricks","last_synced_at":"2025-09-10T15:33:09.060Z","repository":{"id":150430730,"uuid":"192535383","full_name":"karlhorky/github-tricks","owner":"karlhorky","description":"A collection of useful GitHub tricks","archived":false,"fork":false,"pushed_at":"2024-09-29T16:03:30.000Z","size":914,"stargazers_count":22,"open_issues_count":1,"forks_count":4,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-11-29T22:45:29.867Z","etag":null,"topics":["github"],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/karlhorky.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-06-18T12:27:02.000Z","updated_at":"2024-11-14T13:40:32.000Z","dependencies_parsed_at":"2024-02-11T13:42:42.075Z","dependency_job_id":"bceb20f2-ed2b-48f5-b8a9-6e73e536861d","html_url":"https://github.com/karlhorky/github-tricks","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karlhorky%2Fgithub-tricks","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karlhorky%2Fgithub-tricks/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karlhorky%2Fgithub-tricks/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/karlhorky%2Fgithub-tricks/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/karlhorky","download_url":"https://codeload.github.com/karlhorky/github-tricks/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228419545,"owners_count":17916768,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["github"],"created_at":"2024-10-03T15:42:42.512Z","updated_at":"2025-09-10T15:33:08.942Z","avatar_url":"https://github.com/karlhorky.png","language":null,"readme":"# GitHub Tricks\n\nA collection of useful GitHub tricks\n\n## GitHub Actions: Configure `actions/cache` to Skip Cache Restoration on Changes in Directory\n\nTo configure [`actions/cache`](https://github.com/actions/cache) to skip cache restoration on modification of any files or directories inside a Git-tracked directory, configure [`actions/checkout`](https://github.com/actions/checkout) to fetch all commits in all branches and tags (warning: may be expensive) and use a `key` based on the last Git commit hash which modified anything contained in the directory:\n\n```yaml\nname: Skip cache restoration on changes in directory\non: [push]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n        with:\n          # Fetch all commits in all branches and tags\n          fetch-depth: 0\n\n      - name: Get last Git commit hash modifying packages/abc\n        run: |\n          echo \"ABC_HASH=$(git log -1 --pretty=format:%H -- packages/abc)\" \u003e\u003e $GITHUB_ENV\n\n      - name: Cache packages/abc\n        uses: actions/cache@v4\n        with:\n          path: packages/abc\n          key: abc-build-cache-${{ env.ABC_HASH }}\n\n      - name: Build packages/abc\n        run: |\n          pnpm --filter=abc build\n```\n\n## GitHub Actions: Configure `actions/cache` to Skip Cache Restoration on Re-runs\n\nTo configure [`actions/cache`](https://github.com/actions/cache) to skip cache restoration on any re-runs of the workflow (to avoid having to manually delete flaky caches), use [an `if` conditional](https://docs.github.com/en/actions/using-jobs/using-conditions-to-control-job-execution) on the workflow step to check that [`github.run_attempt`](https://docs.github.com/en/actions/learn-github-actions/contexts#github-context:~:text=the%20workflow%20run.-,github.run_attempt,-string) is set to `1`, indicating that it is the first attempt to run the workflow:\n\n```yaml\nname: Skip cache restoration on re-runs\non: [push]\njobs:\n  build:\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n\n      - name: Cache packages/abc\n        # Only restore cache on first run attempt\n        if: ${{ github.run_attempt == 1 }}\n        uses: actions/cache@v4\n        with:\n          path: packages/abc\n          key: abc-build-cache\n\n      - name: Build packages/abc\n        run: |\n          pnpm --filter=abc build\n```\n\n## GitHub Actions: Correct Broken `actions/setup-node` Version Resolution\n\n[Version resolution of Node.js aliases like `lts/*` in `actions/setup-node` is broken as of Aug 2024](https://github.com/actions/setup-node/issues/940#issuecomment-2029638604) (and will probably continue to be broken).\n\nTo resolve this, switch off `actions/setup-node` and instead use the preinstalled `nvm` to install the correct Node.js version based on the alias:\n\n```yaml\n      # Use nvm because actions/setup-node does not install latest versions\n      # https://github.com/actions/setup-node/issues/940\n      - name: Install latest LTS with nvm\n        run: |\n          nvm install 'lts/*'\n          echo \"$(dirname $(nvm which node))\" \u003e\u003e $GITHUB_PATH\n        shell: bash -l {0}\n```\n\nIf you also need caching for pnpm (replacement for the `cache` setting of `actions/setup-node`), follow with this config of [`actions/cache`](https://github.com/actions/cache):\n\n```yaml\n      - name: Get pnpm store directory\n        shell: bash\n        run: |\n          echo \"STORE_PATH=$(pnpm store path --silent)\" \u003e\u003e $GITHUB_ENV\n      - uses: actions/cache@v4\n        name: Setup pnpm cache\n        with:\n          path: ${{ env.STORE_PATH }}\n          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}\n          restore-keys: |\n            ${{ runner.os }}-pnpm-store-\n```\n\n## GitHub Actions: Create Release from `CHANGELOG.md` on New Tag\n\nCreate a new GitHub Release with contents from `CHANGELOG.md` every time a new tag is pushed.\n\n**`.github/workflows/release.yml`**\n\n```yml\nname: Release\non:\n  push:\n    tags:\n      - '*'\npermissions:\n  contents: write\njobs:\n  release:\n    name: Release On Tag\n    if: startsWith(github.ref, 'refs/tags/')\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout the repository\n        uses: actions/checkout@v4\n      - name: Extract the changelog\n        id: changelog\n        run: |\n          TAG_NAME=${GITHUB_REF/refs\\/tags\\//}\n          READ_SECTION=false\n          CHANGELOG_CONTENT=\"\"\n          while IFS= read -r line; do\n            if [[ \"$line\" =~ ^#+\\ +(.*) ]]; then\n              if [[ \"${BASH_REMATCH[1]}\" == \"$TAG_NAME\" ]]; then\n                READ_SECTION=true\n              elif [[ \"$READ_SECTION\" == true ]]; then\n                break\n              fi\n            elif [[ \"$READ_SECTION\" == true ]]; then\n              CHANGELOG_CONTENT+=\"$line\"$'\\n'\n            fi\n          done \u003c \"CHANGELOG.md\"\n          CHANGELOG_CONTENT=$(echo \"$CHANGELOG_CONTENT\" | awk '/./ {$1=$1;print}')\n          echo \"changelog_content\u003c\u003cEOF\" \u003e\u003e $GITHUB_OUTPUT\n          echo \"$CHANGELOG_CONTENT\" \u003e\u003e $GITHUB_OUTPUT\n          echo \"EOF\" \u003e\u003e $GITHUB_OUTPUT\n      - name: Create the release\n        if: steps.changelog.outputs.changelog_content != ''\n        uses: softprops/action-gh-release@v1\n        with:\n          name: ${{ github.ref_name }}\n          body: '${{ steps.changelog.outputs.changelog_content }}'\n          draft: false\n          prerelease: false\n```\n\nCredit: @edloidas in https://github.com/nanostores/nanostores/pull/267\n\n## GitHub Actions: Edit `.json`, `.yml` and `.csv` Files Without Installing Anything\n\n`yq` (similar to `jq`) is preinstalled on GitHub Actions runners, which means you can edit a `.json`, `.yml` or `.csv` file very easily without installing any software.\n\nFor example, the following workflow file would use `yq` to copy all `\"resolutions\"` to `\"overrides\"` in a `package.json` file (and then commit the result using `stefanzweifel/git-auto-commit-action`.\n\n**`.github/workflows/copy-resolutions-to-overrides.yml`**\n\n```yml\nname: Copy Yarn Resolutions to npm Overrides\n\non:\n  push:\n    branches:\n      # Match every branch except for main\n      - '**'\n      - '!main'\n\njobs:\n  build:\n    name: Copy Yarn Resolutions to npm Overrides\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v3\n        # To trigger further `on: [push]` workflow runs\n        # Ref: https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#triggering-further-workflow-runs\n        # Ref: https://github.com/peter-evans/create-pull-request/blob/main/docs/concepts-guidelines.md#push-using-ssh-deploy-keys\n        with:\n          ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}\n\n      - name: Use Node.js\n        uses: actions/setup-node@v4\n        with:\n          node-version: 'lts/*'\n\n      - name: Copy \"resolutions\" object to \"overrides\" in package.json\n        run: yq --inplace --output-format=json '.overrides = .resolutions' package.json\n\n      - name: Install any updated dependencies\n        run: npm install\n\n      - uses: stefanzweifel/git-auto-commit-action@v4\n        with:\n          commit_message: Update Overrides from Resolutions\n```\n\nOr, to copy all `@types/*` and `typescript` packages from `devDependencies` to `dependencies` (eg. for a production build):\n\n```bash\nyq --inplace --output-format=json '.dependencies = .dependencies * (.devDependencies | to_entries | map(select(.key | test(\"^(typescript|@types/*)\"))) | from_entries)' package.json\n```\n\n## GitHub Actions: Free Disk Space\n\nOn GitHub Actions, [runners are only guaranteed 14GB of storage space (disk space)](https://github.com/actions/runner-images/issues/9344#issuecomment-1942811369) ([docs](https://docs.github.com/en/actions/using-github-hosted-runners/using-github-hosted-runners/about-github-hosted-runners#standard-github-hosted-runners-for-public-repositories)), which can lead to the following errors if your workflow uses more than that:\n\n```\nSystem.IO.IOException: No space left on device\n```\n\nor\n\n```\nYou are running out of disk space. The runner will stop working when the machine runs out of disk space. Free space left: 72 MB\n```\n\nOR\n\n```\nENOSPC: no space left on device, write\n```\n\nTo free up disk space for your workflow, use [the Free Disk Space (Ubuntu) action](https://github.com/marketplace/actions/free-disk-space-ubuntu) ([GitHub repo](https://github.com/jlumbroso/free-disk-space)):\n\n```yaml\n      - name: Free Disk Space (Ubuntu)\n        uses: jlumbroso/free-disk-space@v1.3.1\n        with:\n          # Avoid slow clearing of large packages\n          large-packages: false\n```\n\nYou may need to disable some of the clearing options, if your workflow relies upon features or programs which are being removed:\n\n```yaml\n      - name: Free Disk Space (Ubuntu)\n        uses: jlumbroso/free-disk-space@v1.3.1\n        with:\n          # Re-enable swap storage for processes which use more memory\n          # than available and start using swap\n          swap-storage: false\n\n          # Avoid slow clearing of large packages\n          large-packages: false\n```\n\n## GitHub Actions: Only Run When Certain Files Changed\n\nOnly run a GitHub Actions workflow when files matching a pattern have been changed, for example on an update to a pull request:\n\n```yaml\nname: Fix Excalidraw SVG Fonts\non:\n  pull_request:\n    paths:\n      # All .excalidraw.svg files in any folder at any level inside `packages/content-items`\n      - 'packages/content-items/**/*.excalidraw.svg'\n      # All .excalidraw.svg files directly inside `packages/database/.readme/`\n      - 'packages/database/.readme/*.excalidraw.svg'\n```\n\nFor example, the following workflow uses `sed` to add default fonts to Excalidraw diagrams ([no longer needed](https://github.com/excalidraw/excalidraw/issues/4855#issuecomment-2259189107)):\n\n```yaml\n# Workaround to fix fonts in Excalidraw SVGs\n# https://github.com/excalidraw/excalidraw/issues/4855#issuecomment-1513014554\n#\n# Temporary workaround until the following PR is merged:\n# https://github.com/excalidraw/excalidraw/pull/6479\n#\n# TODO: If the PR above is merged, this file can be removed\nname: Fix Excalidraw SVG Fonts\non:\n  pull_request:\n    # Run only when Excalidraw SVG files are added or changed\n    paths:\n      - 'packages/content-items/contentItems/documentation/*.excalidraw.svg'\n      - 'packages/database/.readme/*.excalidraw.svg'\n\njobs:\n  build:\n    # Only run on Pull Requests within the same repository, and not from forks\n    if: github.event.pull_request.head.repo.full_name == github.repository\n    name: Fix Excalidraw SVG Fonts\n    runs-on: ubuntu-latest\n    timeout-minutes: 30\n    steps:\n      - name: Checkout Repo\n        uses: actions/checkout@v4\n        with:\n          ref: ${{ github.head_ref }}\n\n      - name: Fix fonts in Excalidraw SVGs\n        run: |\n          find packages/content-items/contentItems/documentation packages/database/.readme -type f -iname '*.excalidraw.svg' | while read file; do\n            echo \"Fixing fonts in $file\"\n            sed -i.bak 's/Virgil, Segoe UI Emoji/Virgil, '\"'\"'Comic Sans MS'\"'\"', '\"'\"'Segoe Print'\"'\"', '\"'\"'Bradley Hand'\"'\"', '\"'\"'Lucida Handwriting'\"'\"', '\"'\"'Marker Felt'\"'\"', cursive/g' \"$file\"\n            sed -i.bak 's/Helvetica, Segoe UI Emoji/Helvetica, -apple-system,BlinkMacSystemFont, '\"'\"'Segoe UI'\"'\"', '\"'\"'Noto Sans'\"'\"', Helvetica, Arial, sans-serif, '\"'\"'Apple Color Emoji'\"'\"', '\"'\"'Segoe UI Emoji'\"'\"'/g' \"$file\"\n            sed -i.bak 's/Cascadia, Segoe UI Emoji/Cascadia, ui-monospace, SFMono-Regular, '\"'\"'SF Mono'\"'\"', Menlo, Consolas, '\"'\"'Liberation Mono'\"'\"', monospace/g' \"$file\"\n            rm \"${file}.bak\"\n          done\n      - name: Commit files\n        run: |\n          git config user.email github-actions[bot]@users.noreply.github.com\n          git config user.name github-actions[bot]\n          git add packages/content-items/contentItems/documentation/*.excalidraw.svg\n          git add packages/database/.readme/*.excalidraw.svg\n          if [ -z \"$(git status --porcelain)\" ]; then\n            exit 0\n          fi\n          git commit -m \"Fix fonts in Excalidraw SVGs\"\n          git push origin HEAD:${{ github.head_ref }}\n        env:\n          GITHUB_TOKEN: ${{ secrets.EXCALIDRAW_FONT_FIX_GITHUB_TOKEN }}\n```\n\n## GitHub Actions: Push to Pull Request and Re-Run Workflows\n\nIt can be useful to commit and push to a pull request in a GitHub Actions workflow, eg. an automated script that fixes something like [upgrading pnpm patch versions on automatic Renovate dependency upgrades](https://github.com/pnpm/pnpm/issues/5686#issuecomment-1669538653).\n\nOnce your script makes the commit and pushes to the PR, it can also be useful to re-run the workflows on that commit, eg. linting the new commit, so that [GitHub auto-merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/automatically-merging-a-pull-request) can run also on [protected branches with required status checks](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches#require-status-checks-before-merging).\n\n‼️ WARNING: Make sure that you do not create a loop! Once your script creates a commit, the workflow will run your script again on the new commit. On the 2nd run, it **should not** create a new commit, or you will have an endless loop of GitHub Actions workflow runs. 😬 We will revisit this in the script below.\n\n1. First, create a GitHub fine-grained personal access token:\n   1. Visit https://github.com/settings/personal-access-tokens/new\n   2. Fill out **Token name** (repository name + a short reminder), **Expiration** (longest available, 1 year), **Description** (a reminder of the purpose)\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-fine-grained-personal-access-token-name-expiration-description.webp\" alt=\"Screenshot of GitHub fine-grained personal access token form, with the values Token name: 'archive-webpage-browser-extension push', Expiration: 'Custom - 1 year', Description: 'archive-webpage-browser-extension: Fix `pnpm patch` not upgrading patch versions automatically'\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n   3. Under **Repository access**, choose **Only select repositories** and then choose the repository where the workflow will run\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-fine-grained-personal-access-token-repo-access.webp\" alt=\"Screenshot of GitHub fine-grained personal access token Repository Access form, showing the `karlhorky/archive-webpage-browser-extension` selected as the single repository with access\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n   4. Under **Permissions**, expand **Repository permissions**, locate **Contents** and choose **Access: Read and write**\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-fine-grained-personal-access-token-contents-read-write.webp\" alt=\"Screenshot of GitHub fine-grained personal access token form, showing the Contents setting\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n      This will also by default set **Metadata** to **Access: Read-only**\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-fine-grained-personal-access-token-metadata.webp\" alt=\"Screenshot of GitHub fine-grained personal access token form, showing the Metadata setting\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n   5. Review your settings under **Overview** - it should be set to \"2 permissions for 1 of your repositories\" and \"0 Account permissions\"\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-fine-grained-personal-access-token-overview.webp\" alt=\"Screenshot of GitHub fine-grained personal access token form, showing the Overview details\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n   6. If you are satisfied with this, click on **Generate token**.\n   7. This will show you the token on your screen only once, so be careful to copy the token.\n2. Add a repository secret\n   1. In the repository where the workflow will run, visit **Settings** -\u003e **Secrets and variables** -\u003e **Actions** and click on **New repository secret**\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-settings-new-repo-secret.webp\" alt=\"Screenshot of GitHub repository settings page for Actions secrets and variables\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n   2. For **Name**, enter a `SCREAMING_SNAKE_CASE` name that makes it clear that it's a GitHub token (eg. `PNPM_PATCH_UPDATE_GITHUB_TOKEN`) and for **Secret** paste in the token that you copied at the end of step 1 above. Click **Add secret**.\u003cbr /\u003e\u003cbr /\u003e\n      \u003cimg src=\"github-settings-new-repo-secret-form.webp\" alt=\"Screenshot of GitHub repository settings page for Actions secrets and variables\" /\u003e\u003cbr /\u003e\u003cbr /\u003e\n3. Adjust your workflow for the token\n\n   1. Under `uses: actions/checkout`, add a `with:` block including `persist-credentials: false`\n      ```yaml\n      - uses: actions/checkout@v4\n        with:\n          # Disable configuring $GITHUB_TOKEN in local git config\n          persist-credentials: false\n      ```\n   2. ‼️ IMPORTANT: As mentioned above, make sure that you don't create a loop! Make sure that your script which alters files includes some kind of way to exit early, for example checking `git status --porcelain` and running `exit 0` to exit the script early without errors or [by skipping steps based on the last commits](https://joht.github.io/johtizen/build/2022/01/20/github-actions-push-into-repository.html#skip-push-on-auto-commit)\n\n      ```yaml\n      - name: Fix `pnpm patch` not upgrading patch versions automatically\n        run: |\n          # \u003cyour script makes changes here\u003e\n\n          git add package.json pnpm-lock.yaml patches\n          if [ -z \"$(git status --porcelain)\" ]; then\n            echo \"No changes to commit, exiting\"\n            exit 0\n          fi\n\n          # \u003cyour script sets Git credentials and commits here\u003e\n          # \u003cyour script pushes here\u003e\n      ```\n\n   3. Set your Git `user.email` and `user.name` credentials to the GitHub Actions bot and commit:\n\n      ```yaml\n      - name: Fix `pnpm patch` not upgrading patch versions automatically\n        run: |\n          # \u003cyour script makes changes here\u003e\n          # \u003cyour script exits early here\u003e\n\n          git config user.email github-actions[bot]@users.noreply.github.com\n          git config user.name github-actions[bot]\n\n          git commit -m \"Upgrade versions for \\`pnpm patch\\`\"\n\n          # \u003cyour script pushes here\u003e\n      ```\n\n   4. Use the token via `secrets.\u003cname\u003e` in your Git origin in your workflow (credit: [`ad-m/github-push-action`](https://github.com/ad-m/github-push-action/blob/d91a481090679876dfc4178fef17f286781251df/start.sh#L43-L55))\n\n      ```yaml\n      - name: Fix `pnpm patch` not upgrading patch versions automatically\n        run: |\n          # \u003cyour script makes changes here\u003e\n          # \u003cyour script exits early here\u003e\n          # \u003cyour script sets Git credentials and commits here\u003e\n\n          # Credit for oauth2 syntax is the ad-m/github-push-action GitHub Action:\n          # https://github.com/ad-m/github-push-action/blob/d91a481090679876dfc4178fef17f286781251df/start.sh#L43-L5\n          git push https://oauth2:${{ secrets.PNPM_PATCH_UPDATE_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:${{ github.ref }}\n      ```\n\n### Example\n\n```yaml\nname: Fix pnpm patches\non: push\n\njobs:\n  fix-pnpm-patches:\n    name: Fix pnpm patches\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n        with:\n          # Disable configuring $GITHUB_TOKEN in local git config\n          persist-credentials: false\n      - uses: pnpm/action-setup@v3\n        with:\n          version: 'latest'\n      - uses: actions/setup-node@v4\n        with:\n          node-version: 'lts/*'\n          cache: 'pnpm'\n\n      # Fix `pnpm patch` not upgrading patch versions automatically\n      # https://github.com/pnpm/pnpm/issues/5686#issuecomment-1669538653\n      - name: Fix `pnpm patch` not upgrading patch versions automatically\n        run: |\n          # Exit if no patches/ directory in root\n          if [ ! -d patches ]; then\n            echo \"No patches/ directory found in root\"\n            exit 0\n          fi\n\n          ./scripts/fix-pnpm-patches.sh\n\n          git add package.json pnpm-lock.yaml patches\n          if [ -z \"$(git status --porcelain)\" ]; then\n            echo \"No changes to commit, exiting\"\n            exit 0\n          fi\n\n          git config user.email github-actions[bot]@users.noreply.github.com\n          git config user.name github-actions[bot]\n\n          git commit -m \"Upgrade versions for \\`pnpm patch\\`\"\n\n          # Credit for oauth2 syntax is the ad-m/github-push-action GitHub Action:\n          # https://github.com/ad-m/github-push-action/blob/d91a481090679876dfc4178fef17f286781251df/start.sh#L43-L55\n          git push https://oauth2:${{ secrets.PNPM_PATCH_UPDATE_GITHUB_TOKEN }}@github.com/${{ github.repository }}.git HEAD:${{ github.ref }}\n```\n\nPull request with automatic PR commit including workflow checks: https://github.com/karlhorky/archive-webpage-browser-extension/pull/47\n\n\u003cfigure\u003e\n  \u003cimg src=\"github-actions-pr-commit.webp\" alt=\"\" /\u003e\n  \u003cfigcaption\u003e\n    \u003cem\u003e\n      Screenshot of a GitHub PR showing two commits, the first by Renovate bot upgrading dependencies and the second by the automated script shown above. Both commits have status icons to the right of them (one red X and one green checkmark), indicating that the workflows have run on both of them. At the bottom, the PR auto-merge added by the Renovate bot is carried out because the last commit has a green checkmark.\n    \u003c/em\u003e\n  \u003c/figcaption\u003e\n  \u003cbr /\u003e\n  \u003cbr /\u003e\n\u003c/figure\u003e\n\n## GitHub Actions: Create PostgreSQL databases on Windows, macOS and Linux\n\nPostgreSQL databases can be created and used cross-platform on GitHub Actions, either by using the preinstalled PostgreSQL installation or installing PostgreSQL:\n\n- [`windows-latest` and `ubuntu-latest` runners](https://github.com/actions/runner-images#available-images) have PostgreSQL preinstalled\n- [`macos-latest` runners](https://github.com/actions/runner-images#available-images) [don't have PostgreSQL preinstalled (as of May 2024)](https://github.com/actions/runner-images/issues/9029#issuecomment-1856487621)\n\nTo conditionally install PostgreSQL, initialize a cluster, create a user and database and start PostgreSQL cross-platform, use the following GitHub Actions workflow steps (change `database_name`, `username` and `password` to whatever you want):\n\n```yaml\nname: CI\non: push\n\njobs:\n  ci:\n    name: CI\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [windows-latest, macos-latest, ubuntu-latest]\n    timeout-minutes: 15\n    env:\n      PGHOST: localhost\n      PGDATABASE: database_name\n      PGUSERNAME: username\n      PGPASSWORD: password\n    steps:\n      - name: Install PostgreSQL on macOS\n        if: runner.os == 'macOS'\n        run: |\n          brew install postgresql@16\n          # --overwrite: Overwrite pre-installed GitHub Actions PostgreSQL binaries\n          brew link --overwrite postgresql@16\n      - name: Add PostgreSQL binaries to PATH\n        shell: bash\n        run: |\n          if [ \"$RUNNER_OS\" == \"Windows\" ]; then\n            echo \"$PGBIN\" \u003e\u003e $GITHUB_PATH\n          elif [ \"$RUNNER_OS\" == \"Linux\" ]; then\n            echo \"$(pg_config --bindir)\" \u003e\u003e $GITHUB_PATH\n          fi\n      - name: Start preinstalled PostgreSQL\n        shell: bash\n        run: |\n          echo \"Initializing database cluster...\"\n\n          # Convert backslashes to forward slashes in RUNNER_TEMP for Windows Git Bash\n          export PGHOST=\"${RUNNER_TEMP//\\\\//}/postgres\"\n          export PGDATA=\"$PGHOST/pgdata\"\n          mkdir -p \"$PGDATA\"\n\n          # initdb requires file for password in non-interactive mode\n          export PWFILE=\"$RUNNER_TEMP/pwfile\"\n          echo \"postgres\" \u003e \"$PWFILE\"\n          initdb --pgdata=\"$PGDATA\" --username=\"postgres\" --pwfile=\"$PWFILE\"\n\n          echo \"Starting PostgreSQL...\"\n          echo \"unix_socket_directories = '$PGHOST'\" \u003e\u003e \"$PGDATA/postgresql.conf\"\n          pg_ctl start\n\n          echo \"Creating user...\"\n          psql --host \"$PGHOST\" --username=\"postgres\" --dbname=\"postgres\" --command=\"CREATE USER $PGUSERNAME PASSWORD '$PGPASSWORD'\" --command=\"\\du\"\n\n          echo \"Creating database...\"\n          createdb --owner=\"$PGUSERNAME\" --username=\"postgres\" \"$PGDATABASE\"\n```\n\nExample PR: https://github.com/upleveled/preflight-test-project-next-js-passing/pull/152/\n\n## GitHub Flavored Markdown Formatted Table Width\n\nUse `\u0026nbsp;` entities to give a table column a width:\n\n```markdown\n| property\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; | description                           |\n| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |\n| `border-bottom-right-radius`                                                                                                                                                                                                                                                                                                                                               | Defines the shape of the bottom-right |\n```\n\nDemo:\n\n| property\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; | description                           |\n| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- |\n| `border-bottom-right-radius`                                                                                                                                                                                                                                                                                                                                               | Defines the shape of the bottom-right |\n\n## GitHub Flavored Markdown Linking to Anchors in Other Markdown Files\n\nLinking to an anchor in a relative Markdown file path in the same repo (eg. `./windows.md#user-content-xxx`) doesn't currently work on GitHub (Mar 2023). Probably another bug in GitHub's client-side router, maybe fixed sometime.\n\nA workaround is to link to the full GitHub URL with a `www.` subdomain - this will cause a redirect to the non-`www.` version, and scroll to the anchor:\n\n```diff\n-[Expo + React Native](./windows.md#user-content-expo-react-native)\n+[Expo + React Native](https://www.github.com/upleveled/system-setup/blob/main/windows.md#user-content-expo-react-native)\n```\n\n## README Symlinks\n\nWhen in a particular folder (such as the root directory), GitHub displays content from README files underneath the files in that folder:\n\n\u003cimg src=\"github-readme.webp\" alt=\"Screenshot showing readme content below file list\"\u003e\n\nHowever, these README files need to be named `README.md`, `readme.md`, `README.mdx` or `readme.mdx` in order to be recognized. GitHub doesn't display the content of certain common Markdown index filenames such as `index.md` or `index.mdx` ([❓MDX file extension](https://github.com/mdx-js/mdx)) ([as of 18 June 2019](https://twitter.com/karlhorky/status/1140962752858677249)).\n\nGitHub does however follow symlinks named `README.md`, `readme.md`, `README.mdx` and `readme.mdx`. See example here: [mdx-deck root folder](https://github.com/jxnblk/mdx-deck), [mdx-deck symlink README.md](https://github.com/jxnblk/mdx-deck/blob/master/README.md)\n\nSo if you want to use another file (also in a subdirectory) as the contents displayed within a directory, create a symlink pointing at it:\n\n```sh\nln -s index.md README.md\n```\n\n### Shell Script: Create README Symlinks\n\nIf you have many directories with `index.mdx` files that you want to display as the readme content when you enter those directories on the web version of GitHub, you can run this script in the containing directory.\n\n```sh\n# Create symlinks for all directories within the current directory that\n# do not yet have README.mdx files.\nfind . -mindepth 1 -maxdepth 1 -type d '!' -exec test -e \"{}/README.mdx\" ';' -print0 | while IFS= read -r -d $'\\0' line; do\n    cd $line \u0026\u0026 ln -s index.mdx README.mdx \u0026\u0026 cd ..\ndone\n```\n\n## Refined GitHub: Sticky Comment Headers\n\nKeeping the context and actions from the comment header in view can be especially useful for long comments:\n\nhttps://github.com/user-attachments/assets/0a38d7e2-d16c-4d52-b250-c51a050af501\n\nFirst, install and set up the [Refined GitHub](https://github.com/refined-github/refined-github) browser extension. In the Refined GitHub options under Custom CSS, add the following CSS from [@SunsetTechuila](https://github.com/SunsetTechuila)'s closed PR https://github.com/refined-github/refined-github/pull/8544\n\n```css\n/* https://github.com/refined-github/refined-github/issues/8463#issuecomment-3094626175 */\n\n/* Issue body header */\n[class^=\"IssueBodyHeader-module__IssueBodyHeaderContainer\"],\n/* Issue comment header */\n[data-testid='comment-header'],\n/* PR body/comment header */\n.timeline-comment-header {\n\tposition: sticky;\n\ttop: calc(var(--base-sticky-header-height, 0px) + 56px);\n\tz-index: 3;\n\tbackground: var(--bgColor-muted, var(--color-canvas-subtle)) !important;\n}\n\n[id^=\"gistcomment\"] .timeline-comment-header {\n\ttop: 0;\n}\n\n/* Show menus on top of headers */\n.js-comment-container:has(details[open]) .timeline-comment-header {\n\tz-index: 4;\n}\n\n[class^=\"IssueBodyHeader-module__IssueBodyHeaderContainer\"],\n[data-testid=\"comment-header\"] {\n\tborder-radius: 0;\n}\n\n/* Issue body container */\n[data-testid=\"issue-body\"] [class^=\"Box\"]:has(\u003e #issue-body-viewer),\n/* Issue comment container */\n[class^=\"IssueCommentViewer-module__IssueCommentContent\"] {\n\tborder-radius: var(--borderRadius-medium);\n\toverflow: clip;\n}\n\n@supports (anchor-name: --test) {\n\t[app-name=\"issues-react\"] {\n\t\t[class*=\"ActivityHeader-module__activityHeader\"]\n\t\t\tbutton[aria-haspopup=\"true\"][aria-expanded=\"true\"] {\n\t\t\tanchor-name: --header;\n\t\t}\n\n\t\t[class^=\"prc-Overlay-Overlay\"][data-variant=\"anchored\"]:has(\n\t\t\t\t.octicon-quote,\n\t\t\t\t[class*=\"scrollableEditHistoryList\"]\n\t\t\t) {\n\t\t\tposition: fixed !important;\n\t\t\tposition-anchor: --header;\n\t\t\ttop: anchor(bottom) !important;\n\t\t}\n\t}\n}\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarlhorky%2Fgithub-tricks","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkarlhorky%2Fgithub-tricks","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkarlhorky%2Fgithub-tricks/lists"}