Skip to content

release!: v3#37

Merged
avidal merged 14 commits intomainfrom
avidal/v3
Mar 26, 2026
Merged

release!: v3#37
avidal merged 14 commits intomainfrom
avidal/v3

Conversation

@avidal
Copy link
Copy Markdown
Collaborator

@avidal avidal commented Jan 23, 2026

commit-headless v3.0.0

This PR contains breaking changes to the CLI and action interfaces, along with new features.

Breaking Changes

push command

The push command no longer accepts commit arguments. It now automatically determines which local commits need to be pushed by comparing local HEAD with the remote branch HEAD.

Before:

commit-headless push -T owner/repo --branch feature <commit1> <commit2>

After:

commit-headless push -T owner/repo --branch feature

The commits action input has been removed.

commit command

The commit command no longer accepts file arguments. It now reads from the git staging area, similar to git commit.

Before:

commit-headless commit -T owner/repo --branch feature -m "message" file1.txt file2.txt

After:

git add file1.txt file2.txt
commit-headless commit -T owner/repo --branch feature -m "message"

The files action input has been removed.

New Features

--force for commit and push commands

When --force is set, --head-sha is used directly as the parent of the first pushed commit, bypassing the remote HEAD safety check. The branch ref is force-updated even if the push is not a fast-forward. This is useful for, e.g., pushing rebased commits.

Without this, there is no way for commit-headless to force push.

replay command

New command to replay existing remote commits as signed commits. Useful when an action or bot creates unsigned commits that you want to replace with signed versions.

commit-headless replay -T owner/repo --branch feature --since abc123

The command fetches the remote branch, extracts commits since the specified base, recreates them as signed commits, and force-updates the branch ref.

Action usage:

- uses: DataDog/commit-headless@action/v3.0.0
  with:
    branch: ${{ github.ref_name }}
    since: ${{ github.sha }}
    command: replay

File mode preservation

File modes (such as the executable bit) are now preserved when pushing commits. Previously all files were created with mode 100644.

GitHub Actions logging

When running in GitHub Actions, output now uses workflow commands:

  • Commit operations are grouped for cleaner logs
  • Success/failure notices appear in the workflow summary
  • Warnings and errors use appropriate annotation levels

Internal Changes

  • Switched from GraphQL API to REST API
  • Added CI test workflow for integration testing on pull requests
  • Release workflow now verifies binaries on both amd64 and arm64 before releasing

@avidal avidal marked this pull request as ready for review January 23, 2026 20:56
@avidal avidal requested a review from a team as a code owner January 23, 2026 20:56
avidal added 11 commits March 12, 2026 10:22
This patch is an internal-only change to swap from using the GraphQL API
to using the REST API, which will unlock future changes due to the REST
API being more powerful.
Specifying which commits to push started to become untenable. In an
effort to simplify, push now no longer takes any non-flag arguments.
Instead, it will always push local commits that do not exist on the
remote.

Note that `--head-sha` is still recommended to be used as a safety
check to ensure the remote has not moved from where you expected.

If the remote HEAD is not an ancestor of the local HEAD, the push will
fail due to diverged history.
Similar to the push command simplification, the commit command had some
bad UX. The original intent was to allow folks to use `commit-headless commit`
when they didn't even have the repository itself checked out, but in
practice that hasn't been seen (consider that your changes tend to be in
CI jobs where the code is available).

Instead of requiring users to supply the list of changed files, the
`commit` command now operates like `git commit && git push` and takes
whatever changes have been staged.
Previously, commit-headless would just print all log information to
stderr and save stdout purely for the final pushed ref. It was generally
fine, but we can improve it.

Now, commit-headless detects when it's running in an Action context and
prints out messages to standard output using proper log group workflow
commands while leaving non-Action usage alone.

Example:
  ▶ Pushing to owner/repo (branch: main)    [collapsible]
    Commits: abc123, def456
    Remote head commit: 111222
    ▶ Commit abc12345: Update README        [collapsible]
      Author: A U Thor <a@b.com>
      Changed files: 1
        - MODIFY: README.md
  ℹ️ Pushed 1 commit(s) to https://github.com/owner/repo/commits/main
This patch adds commit-headless replay, useful for situations where you
want to replace a series of existing remote commits with signed equivalents.

See README.md or `commit-headless reply --help` for more.
Some callers need to be able to force push. If they have a complex
workflow that involves local rebasing, for instance, they should be able
to force push.

To force push (or commit), you must specify `--head-sha` and `--force`.
If set, the remote HEAD check is skipped and instead `--head-sha` is
used as the parent for the first created commit (or only commit in the
case of the commit command).

refs #45
@avidal avidal force-pushed the avidal/v3 branch 3 times, most recently from 6918b50 to 6f5e553 Compare March 23, 2026 20:49
Sometimes commits made by the API are not signed. We've seen this
intermittently internally.

Instead of allowing unsigned commits to be created, we're now verifying
created commits. If a created commit is unsigned, commit-headless will
make up to `--sign-attempts` attempts (default 5) with exponential
backoff before hard failing.

While this will technically create up to 5 new commits on the remote,
the actual branch reference is only updated once the signed commit is
created. The dangling commits will be removed by GitHub during normal
garbage collection.

As part of this, we only update the branch pointer after *all* commits
are created, not when *each* commit is created. This means a failure in
the middle of a push of 5 commits will not leave you with a subset of
remote commits.
@avidal avidal force-pushed the avidal/v3 branch 2 times, most recently from 77a93f5 to ec9e2b3 Compare March 23, 2026 21:21
@avidal avidal merged commit 0c4d0e2 into main Mar 26, 2026
14 checks passed
@avidal avidal deleted the avidal/v3 branch March 26, 2026 13:07
github-actions Bot added a commit that referenced this pull request Mar 26, 2026
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants