{"id":13727221,"url":"https://github.com/tibdex/github-rebase","last_synced_at":"2025-05-07T22:30:55.585Z","repository":{"id":122132180,"uuid":"144222455","full_name":"tibdex/github-rebase","owner":"tibdex","description":"⏭ Rebase a pull request using the GitHub REST API","archived":true,"fork":false,"pushed_at":"2020-09-05T17:54:24.000Z","size":290,"stargazers_count":24,"open_issues_count":0,"forks_count":11,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-18T01:29:16.782Z","etag":null,"topics":["autosquash","git","github","github-rest-v3","rebase"],"latest_commit_sha":null,"homepage":"","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/tibdex.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":"2018-08-10T01:42:06.000Z","updated_at":"2023-01-28T12:58:16.000Z","dependencies_parsed_at":"2023-06-03T20:00:22.529Z","dependency_job_id":null,"html_url":"https://github.com/tibdex/github-rebase","commit_stats":{"total_commits":31,"total_committers":3,"mean_commits":"10.333333333333334","dds":0.09677419354838712,"last_synced_commit":"185dec19e80429dca351a7d753fea5a7bded4897"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibdex%2Fgithub-rebase","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibdex%2Fgithub-rebase/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibdex%2Fgithub-rebase/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tibdex%2Fgithub-rebase/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tibdex","download_url":"https://codeload.github.com/tibdex/github-rebase/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252965244,"owners_count":21832850,"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":["autosquash","git","github","github-rest-v3","rebase"],"created_at":"2024-08-03T01:03:44.783Z","updated_at":"2025-05-07T22:30:55.185Z","avatar_url":"https://github.com/tibdex.png","language":"TypeScript","readme":"[![npm version](https://img.shields.io/npm/v/github-rebase.svg)](https://npmjs.org/package/github-rebase) [![build status](https://img.shields.io/circleci/project/github/tibdex/github-rebase.svg)](https://circleci.com/gh/tibdex/github-rebase)\r\n\r\n# Goal\r\n\r\n`github-rebase` rebases a pull request using the GitHub REST API. It doesn't merge the pull request, it only rebases its head branch on top of its base branch.\r\n\r\n`github-rebase` has built-in support for [autosquashing](https://git-scm.com/docs/git-rebase#git-rebase---autosquash). Commits with subject starting with `fixup!` or `squash!` will be rearranged and squashed automatically.\r\n\r\nSee [Autorebase](https://github.com/tibdex/autorebase) if you want to automatically rebase and merge green and up-to-date pull requests.\r\n\r\n# Maintenance update\r\n\r\nThis library was developed to make [Autorebase](https://github.com/tibdex/autorebase) possible but focus has shifted to the development of its successor: [Autosquash](https://github.com/marketplace/actions/autosquash).\r\n\r\nThis project will thus stop receiving updates.\r\n\r\n# Usage\r\n\r\n```javascript\r\nimport { rebasePullRequest } from \"github-rebase\";\r\n\r\nconst example = async () =\u003e {\r\n  const newHeadSha = await rebasePullRequest({\r\n    // An already authenticated instance of https://www.npmjs.com/package/@octokit/rest.\r\n    octokit,\r\n    // The username of the repository owner.\r\n    owner: \"tibdex\",\r\n    // The number of the pull request to rebase.\r\n    pullRequestNumber: 1337,\r\n    // The name of the repository.\r\n    repo: \"my-cool-project\",\r\n  });\r\n};\r\n```\r\n\r\n`github-rebase` can run on Node.js and in recent browsers.\r\n\r\n## Troubleshooting\r\n\r\n`github-rebase` uses [`debug`](https://www.npmjs.com/package/debug) to log helpful information at different steps of the rebase process. To enable these logs, set the `DEBUG` environment variable to `github-rebase`.\r\n\r\n# How it Works\r\n\r\nThe GitHub REST API doesn't provide a direct endpoint to rebase a pull request without merging it.\r\nHowever, a rebase can be seen as one or multiple cherry-pick operations where the head and base branches would be reversed.\r\n`github-rebase` thus relies on [`github-cherry-pick`](https://www.npmjs.com/package/github-cherry-pick) to perform all the relevant cherry-pick operations needed to perform a rebase.\r\n\r\n## Step by Step\r\n\r\nLet's say we have this Git state:\r\n\r\n\u003c!--\r\ntouch A.txt B.txt C.txt D.txt\r\ngit init\r\ngit add A.txt\r\ngit commit --message A\r\ngit checkout -b feature\r\ngit add B.txt\r\ngit commit --message B\r\ngit add C.txt\r\ngit commit --message C\r\ngit checkout master\r\ngit add D.txt\r\ngit commit --message D\r\n--\u003e\r\n\r\n```\r\n* 017bffc (feature) C\r\n* 5b5b6e2 B\r\n| * 3c70b13 (HEAD -\u003e master) D\r\n|/\r\n* a5c5755 A\r\n```\r\n\r\nand a pull request where `master` is the base branch and `feature` the head branch. GitHub would say: \"The user wants to merge 2 commits into `master` from `feature`\".\r\n\r\nTo rebase the pull request, `github-rebase` would then take the following steps:\r\n\r\n1.  Create a `temp` branch from `master` with [POST /repos/:owner/:repo/git/refs](https://developer.github.com/v3/git/refs/#create-a-reference).\r\n    \u003c!--\r\n    git checkout -b temp\r\n    --\u003e\r\n    ```\r\n    * 017bffc (feature) C\r\n    * 5b5b6e2 B\r\n    | * 3c70b13 (HEAD -\u003e temp, master) D\r\n    |/\r\n    * a5c5755 A\r\n    ```\r\n2.  Cherry-pick `5b5b6e2` and `017bffc` on top of `temp` with [`github-cherry-pick`](https://www.npmjs.com/package/github-cherry-pick).\r\n    \u003c!--\r\n    git cherry-pick 5b5b6e2 017bffc\r\n    --\u003e\r\n    ```\r\n    * 6de5ac0 (HEAD -\u003e temp) C\r\n    * 544d948 B\r\n    * 3c70b13 (master) D\r\n    | * 017bffc (feature) C\r\n    | * 5b5b6e2 B\r\n    |/\r\n    * a5c5755 A\r\n    ```\r\n3.  Check that `feature`'s reference is still `017bffc` with [GET /repos/:owner/:repo/git/refs/:ref](https://developer.github.com/v3/git/refs/#get-a-reference) or abort by jumping to step 5.\r\n4.  Set `feature`'s reference to the same as `temp` with [PATCH /repos/:owner/:repo/git/refs/:ref](https://developer.github.com/v3/git/refs/#update-a-reference).\r\n    \u003c!-- no corresponding Git CLI operation --\u003e\r\n    ```\r\n    * 6de5ac0 (HEAD -\u003e feature, temp) C\r\n    * 544d948 B\r\n    * 3c70b13 (master) D\r\n    * a5c5755 A\r\n    ```\r\n5.  Delete the `temp` branch with [DELETE /repos/:owner/:repo/git/refs/:ref](https://developer.github.com/v3/git/refs/#delete-a-reference) and we're done!\r\n      \u003c!--\r\n      git branch --delete temp\r\n      --\u003e\r\n    ```\r\n    * 6de5ac0 (HEAD -\u003e feature) C\r\n    * 544d948 B\r\n    * 3c70b13 (master) D\r\n    * a5c5755 A\r\n    ```\r\n\r\n## Atomicity\r\n\r\n`github-rebase` tries as hard as possible to be atomic.\r\n\r\n- The underlying cherry-pick operations are atomic.\r\n- The only thing that can go wrong is when a commit is pushed on the pull request head branch between steps 3 and 4 explained above.\r\n  In that case, the commit that was just pushed won't be part of the pull request head branch anymore.\r\n  It doesn't mean that this particular commit is completely lost.\r\n  Commits are immutable and, once pushed, they can always be retrieved from their SHA.\r\n  See [Recovering a commit from GitHub’s Reflog](https://objectpartners.com/2014/02/11/recovering-a-commit-from-githubs-reflog/) and [this Stack Overflow comment](https://stackoverflow.com/questions/4367977/how-to-remove-a-dangling-commit-from-github/32840385#comment38892952_4368673) that shows that GitHub keeps views of orphan commits in cache for a **long time**.\r\n\r\n  There is no way to fix this issue as the GitHub REST API doesn't provide a compare-and-swap endpoint for updating references like it does for merges.\r\n  Hopefully the issue should almost never occur since the window during which the head branch is vulnerable usually lasts less than 100 milliseconds (the average GitHub REST API response time).\r\n\r\nThere are [tests](tests/index.test.js) for it.\r\n","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftibdex%2Fgithub-rebase","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftibdex%2Fgithub-rebase","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftibdex%2Fgithub-rebase/lists"}