Skip to content

push_files leaves an orphan branch at the default branch's head when the push fails #3755

Open

Description

@rafe-walker

Describe the bug

When branch does not exist, push_files creates it from the default branch first (createReferenceFromDefaultBranch) and only then builds the tree and commit. If the tree or commit step fails, the new ref is not rolled back. The caller gets an error, but a branch pointing at the default branch's head stays behind. A retry then pushes onto that leftover branch, and it shows up in branch lists.

When the branch already exists, the same failure leaves no partial commit, so only the new-branch path is affected.

Silently creating a branch that doesn't exist is already raised as a question in #3473 (item 6). This issue is only about the ref left behind when the push then fails.

Code (main 99d6d65, unchanged since v2.1.0): pkg/github/repositories.go:1767-1772 (ref created when the branch is missing), :1795-1800 (same for the empty-repo path), then CreateTree at :1809 and CreateCommit/UpdateRef after it. Helper: pkg/github/repositories_helper.go:75. Open PR #3288 keeps the ensure-ref-first order (ensurePushFilesBranchRef), so it would not change this.

Affected version

v2.1.0 (image sha256:f6056fc1…0f8a, commit 4bcdcdf) and main nightly (image sha256:48bc16d0…338f, revision 99d6d65).

Steps to reproduce the behavior

  1. Make sure the branch new-branch does not exist.
  2. Call it with one valid file and one path that CreateTree rejects:
    {"name":"push_files","arguments":{"owner":"OWNER","repo":"REPO","branch":"new-branch","message":"push","files":[{"path":"p4/ok.txt","content":"ok"},{"path":".git/config","content":"x"}]}}
    
  3. Result: isError with failed to create tree: tree.path contains a malformed path component.
  4. GET /repos/OWNER/REPO/git/ref/heads/new-branch returns 200, and the branch points at the default branch's head commit.

Expected vs actual behavior

Expected: a failed push leaves the repository unchanged, with no new branch.

Actual: the error is returned and an orphan branch exists at the default branch's head.

Suggested fix: tree and commit objects don't need a ref. Create the tree and the commit (parent = default branch head) first, then create the new ref directly at the new commit. Alternatively, delete the ref on any later failure.

Logs

push_files branch=new-branch -> ISERROR failed to create tree: tree.path contains a malformed path component
GET git/ref/heads/new-branch -> 200, object.sha = faf1b251… (= default branch head)   [v2.1.0 and main]

Found during an independent audit of v2.1.0 on a throwaway org and private test repo. Prepared with AI assistance (Claude Code); reproduced by two independent test runs before filing.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions