{"id":18486289,"url":"https://github.com/maxgfr/github-commit-push-file","last_synced_at":"2026-02-08T19:25:12.336Z","repository":{"id":37025655,"uuid":"496302350","full_name":"maxgfr/github-commit-push-file","owner":"maxgfr","description":"Github action which lets you to commit and push a file to a repository","archived":false,"fork":false,"pushed_at":"2025-03-11T18:40:52.000Z","size":301,"stargazers_count":3,"open_issues_count":16,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T03:34:20.253Z","etag":null,"topics":["actions","commit","commit-message","files","github","github-actions","push"],"latest_commit_sha":null,"homepage":"https://github.com/marketplace/actions/github-commit-push-file","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/maxgfr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2022-05-25T16:07:07.000Z","updated_at":"2023-05-02T15:31:14.000Z","dependencies_parsed_at":"2023-02-08T04:55:16.752Z","dependency_job_id":"c69b49b9-0eb3-44b6-988f-c821dd222a39","html_url":"https://github.com/maxgfr/github-commit-push-file","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Fgithub-commit-push-file","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Fgithub-commit-push-file/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Fgithub-commit-push-file/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/maxgfr%2Fgithub-commit-push-file/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/maxgfr","download_url":"https://codeload.github.com/maxgfr/github-commit-push-file/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247912789,"owners_count":21017045,"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":["actions","commit","commit-message","files","github","github-actions","push"],"created_at":"2024-11-06T12:48:53.992Z","updated_at":"2026-02-08T19:25:12.332Z","avatar_url":"https://github.com/maxgfr.png","language":"TypeScript","readme":"# github-commit-push-file [![View Action](https://img.shields.io/badge/view-github%20action-yellow.svg)](https://github.com/marketplace/actions/github-commit-push-file) [![pipeline](https://img.shields.io/github/actions/workflow/status/maxgfr/github-commit-push-file/test-build.yml)](https://github.com/maxgfr/github-commit-push-file/actions/workflows/test-build.yml)\n\n`maxgfr/github-commit-push-file` is a [GitHub Action](https://github.com/features/actions) which lets you commit and push files to a repository with advanced options like commit signing, custom author, and selective file staging.\n\n## Features\n\n- ✅ Commit and push files to a repository\n- ✅ GPG commit signing support with enhanced validation\n- ✅ Custom author name and email\n- ✅ Selective file staging (specific files or all, with quote support for filenames with spaces)\n- ✅ Target branch configuration\n- ✅ Skip if no changes option\n- ✅ Force push option\n- ✅ Outputs for commit status and SHA\n- ✅ Working directory support for monorepos\n\n## Usage\n\n### Basic Usage\n\n```yaml\nname: 'commit-and-push'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file\n        run: echo \"Hello World\" \u003e\u003e hello.txt\n\n      - name: Commit and push the file\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: add hello.txt'\n```\n\n### With Change Detection (Skip if No Changes)\n\nThis is useful for scheduled workflows where you only want to commit if there are actual changes:\n\n````yaml\nname: 'scheduled-update'\non:\n  schedule:\n    - cron: '0 0 * * *'\n\njobs:\n  update:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Run update script\n        run: node ./scripts/update-data.js\n\n      - name: Commit and push (if changes)\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: update data'\n          files: 'data/output.json'\n          skip_if_no_changes: 'true'\n        ```\n\n        Note: If no changes are detected, the action will skip the commit and push and set the `committed` output to `false`.\n\n### With Working Directory\n\nThis is useful for monorepos or when you want to commit files in a specific subdirectory:\n\n```yaml\nname: 'commit-in-subdirectory'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file in subdirectory\n        run: echo \"Content\" \u003e\u003e packages/my-package/file.txt\n\n      - name: Commit and push in subdirectory\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: update package file'\n          work_dir: 'packages/my-package'\n````\n\n### With GPG Commit Signing\n\n```yaml\nname: 'signed-commit'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file\n        run: echo \"Signed content\" \u003e\u003e signed.txt\n\n      - name: Commit and push with signature\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: add signed file'\n          sign_commit: 'true'\n          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}\n          gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }}\n```\n\n### With Custom Author\n\n```yaml\nname: 'custom-author'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file\n        run: echo \"Bot content\" \u003e\u003e bot.txt\n\n      - name: Commit and push with custom author\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: automated update'\n          author_name: 'My Bot'\n          author_email: 'bot@example.com'\n```\n\n### Pushing to a Different Branch\n\n```yaml\nname: 'push-to-branch'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file\n        run: echo \"Feature content\" \u003e\u003e feature.txt\n\n      - name: Commit and push to feature branch\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'feat: add feature file'\n          branch: 'feature-branch'\n          force_push: 'false'\n```\n\n### Using Outputs\n\n```yaml\nname: 'with-outputs'\non:\n  push:\n    branches: [main]\n\njobs:\n  action:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions/checkout@v4\n\n      - name: Create a file\n        run: echo \"Content\" \u003e\u003e file.txt\n\n      - name: Commit and push\n        id: commit\n        uses: maxgfr/github-commit-push-file@main\n        with:\n          commit_message: 'chore: add file'\n          skip_if_no_changes: 'true'\n\n      - name: Check if committed\n        run: |\n          if [ \"${{ steps.commit.outputs.committed }}\" == \"true\" ]; then\n            echo \"Commit was made with SHA: ${{ steps.commit.outputs.commit_sha }}\"\n          else\n            echo \"No changes were committed\"\n          fi\n```\n\n## Inputs\n\n| Name                 | Type    | Required | Default                                 | Description                                                                               |\n| -------------------- | ------- | -------- | --------------------------------------- | ----------------------------------------------------------------------------------------- |\n| `commit_message`     | string  | **yes**  | -                                       | The commit message                                                                        |\n| `files`              | string  | no       | `-A`                                    | Files to add (space-separated). Use `-A` for all files. Supports quoted paths with spaces |\n| `branch`             | string  | no       | current branch                          | Target branch to push to                                                                  |\n| `author_name`        | string  | no       | `GITHUB_ACTOR`                          | The name of the commit author                                                             |\n| `author_email`       | string  | no       | `GITHUB_ACTOR@users.noreply.github.com` | The email of the commit author                                                            |\n| `sign_commit`        | boolean | no       | `false`                                 | Whether to sign the commit with GPG                                                       |\n| `gpg_private_key`    | string  | no       | -                                       | GPG private key (base64 encoded) for signing commits                                      |\n| `gpg_passphrase`     | string  | no       | -                                       | Passphrase for the GPG private key                                                        |\n| `force_push`         | boolean | no       | `true`                                  | Whether to force push                                                                     |\n| `skip_if_no_changes` | boolean | no       | `true`                                  | Skip commit and push if there are no changes                                              |\n| `work_dir`           | string  | no       | repository root                         | Working directory to execute git commands in                                              |\n\n### Deprecated Inputs\n\n| Name          | Type   | Description                                  |\n| ------------- | ------ | -------------------------------------------- |\n| `commit_name` | string | **Deprecated**: Use `commit_message` instead |\n\n## Outputs\n\n| Name         | Type   | Description                                         |\n| ------------ | ------ | --------------------------------------------------- |\n| `committed`  | string | Whether a commit was made (`true` or `false`)       |\n| `commit_sha` | string | The SHA of the commit (empty if no commit was made) |\n\n## GPG Signing Setup\n\nTo use GPG commit signing, you need to:\n\n1. **Generate a GPG key** (if you don't have one):\n\n   ```bash\n   gpg --full-generate-key\n   ```\n\n2. **Export your private key** (base64 encoded):\n\n   ```bash\n   gpg --armor --export-secret-keys YOUR_KEY_ID | base64 -w 0\n   ```\n\n3. **Add the key to GitHub Secrets**:\n   - Go to your repository settings\n   - Navigate to Secrets and variables \u003e Actions\n   - Add `GPG_PRIVATE_KEY` with the base64-encoded key\n   - Add `GPG_PASSPHRASE` with your key's passphrase (if any)\n\n4. **Add the public key to your GitHub account**:\n   - Export: `gpg --armor --export YOUR_KEY_ID`\n   - Go to GitHub Settings \u003e SSH and GPG keys \u003e New GPG key\n   - Paste the public key\n\n## Migration from v1\n\nIf you're upgrading from an older version, note these changes:\n\n- `commit_name` has been renamed to `commit_message` (the old name still works but is deprecated)\n- New features: `files`, `branch`, `author_name`, `author_email`, `sign_commit`, `gpg_private_key`, `gpg_passphrase`, `force_push`, `skip_if_no_changes`, `work_dir`\n- New outputs: `committed`, `commit_sha`\n- Enhanced GPG key validation\n- Improved error handling\n\n## Internal Functions Documentation\n\nThe action includes several utility functions for enhanced reliability:\n\n### `isValidBase64(str: string): boolean`\n\n**Purpose**: Validates if a string is properly base64 encoded.\n\n**Parameters**:\n\n- `str` - String to validate\n\n**Returns**: `true` if valid base64, `false` otherwise\n\n**Effects**: None (pure function)\n\n**Used by**: `setupGpg()` for validating GPG keys\n\n---\n\n### `safeUnlinkSync(filePath: string): void`\n\n**Purpose**: Safely removes a file if it exists, without throwing errors.\n\n**Parameters**:\n\n- `filePath` - Path to the file to remove\n\n**Returns**: None\n\n**Effects**: Removes the file at `filePath` if it exists\n\n**Used by**: `setupGpg()` for cleanup in finally block\n\n---\n\n### `safeRmdirSync(dirPath: string): void`\n\n**Purpose**: Safely removes a directory if it exists and is empty, without throwing errors.\n\n**Parameters**:\n\n- `dirPath` - Path to the directory to remove\n\n**Returns**: None\n\n**Effects**: Removes the directory at `dirPath` if it exists\n\n**Used by**: `setupGpg()` for cleanup in finally block\n\n---\n\n### `safeMkdirSync(dirPath: string, mode: number): void`\n\n**Purpose**: Safely creates a directory with proper permissions if it doesn't exist.\n\n**Parameters**:\n\n- `dirPath` - Path to the directory to create\n- `mode` - File permissions mode (e.g., `0o700` for private directory)\n\n**Returns**: None\n\n**Effects**: Creates the directory at `dirPath` with specified permissions if it doesn't exist\n\n**Used by**: `setupGpg()` for creating `.gnupg` directory\n\n---\n\n### `getInputs(): ActionInputs`\n\n**Purpose**: Gets and validates action inputs from environment variables.\n\n**Parameters**: None\n\n**Returns**: `ActionInputs` object containing all configuration\n\n**Effects**:\n\n- Validates `commit_message` is provided (throws error if missing)\n- Trims whitespace from commit message\n- Logs warning for deprecated `commit_name` input\n\n**Throws**: Error if `commit_message` is missing\n\n---\n\n### `setupGpg(gpgPrivateKey: string, gpgPassphrase: string): Promise\u003cstring\u003e`\n\n**Purpose**: Sets up GPG signing for git commits.\n\n**Parameters**:\n\n- `gpgPrivateKey` - Base64 encoded GPG private key\n- `gpgPassphrase` - Optional passphrase for the GPG key\n\n**Returns**: The GPG key ID\n\n**Effects**:\n\n- Validates base64 encoding of the key\n- Validates decoded key is a valid PGP key\n- Imports the key into GPG\n- Configures git to use the key for signing\n- Creates temporary files that are cleaned up in finally block\n\n**Throws**: Error if:\n\n- GPG key is not valid base64\n- Decoded key is not a valid PGP key\n- Key ID cannot be extracted\n- GPG commands fail\n\n**Side Effects**:\n\n- Creates and removes temporary files\n- Modifies git configuration\n- May modify `.gnupg` directory in user home\n\n---\n\n### `hasChanges(files: string): Promise\u003cboolean\u003e`\n\n**Purpose**: Adds files to git staging area and checks for changes.\n\n**Parameters**:\n\n- `files` - Files pattern ('-A' for all files, or space-separated list with quote support)\n\n**Returns**: `true` if there are staged changes, `false` otherwise\n\n**Effects**:\n\n- Adds specified files to git staging area\n- Runs `git diff --cached --quiet` to detect changes\n\n**Side Effects**:\n\n- Modifies git index (staging area)\n\n---\n\n### `run(): Promise\u003cvoid\u003e`\n\n**Purpose**: Main execution function for the GitHub Action.\n\n**Parameters**: None\n\n**Returns**: Promise that resolves when complete\n\n**Effects**:\n\n- Gets and validates inputs\n- Changes to working directory if specified\n- Configures git user\n- Sets up GPG signing if enabled\n- Checks for changes\n- Creates commit (or empty commit if no changes and `skip_if_no_changes=false`)\n- Gets commit SHA\n- Pushes to remote\n- Sets action outputs\n\n**Throws**: Error for various failure conditions, all caught and reported via `core.setFailed()`\n\n**Side Effects**:\n\n- May change current working directory\n- Modifies git configuration\n- Creates git commits\n- Pushes to remote repository\n\n## License\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgfr%2Fgithub-commit-push-file","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmaxgfr%2Fgithub-commit-push-file","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmaxgfr%2Fgithub-commit-push-file/lists"}