{"id":16665329,"url":"https://github.com/larsbrinkhoff/fearless-git","last_synced_at":"2025-04-09T19:11:32.345Z","repository":{"id":145662943,"uuid":"167131877","full_name":"larsbrinkhoff/fearless-git","owner":"larsbrinkhoff","description":"Rewrite Git History Like There's No Tomorrow","archived":false,"fork":false,"pushed_at":"2019-08-22T05:58:48.000Z","size":14,"stargazers_count":14,"open_issues_count":5,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-09T19:11:15.766Z","etag":null,"topics":["git","rebase","source-control"],"latest_commit_sha":null,"homepage":null,"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/larsbrinkhoff.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-01-23T06:43:28.000Z","updated_at":"2025-03-11T08:29:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"3438642c-4d25-4529-85e4-a87853044890","html_url":"https://github.com/larsbrinkhoff/fearless-git","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/larsbrinkhoff%2Ffearless-git","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsbrinkhoff%2Ffearless-git/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsbrinkhoff%2Ffearless-git/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/larsbrinkhoff%2Ffearless-git/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/larsbrinkhoff","download_url":"https://codeload.github.com/larsbrinkhoff/fearless-git/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248094989,"owners_count":21046770,"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":["git","rebase","source-control"],"created_at":"2024-10-12T11:06:43.769Z","updated_at":"2025-04-09T19:11:32.336Z","avatar_url":"https://github.com/larsbrinkhoff.png","language":null,"readme":"# Fearless Git\n\nLearn to love interactive rebasing in a handful of easy steps!\n\n### Table of contents\n\n1. [About](#about)\n2. [A little bit of background](#a-little-bit-of-background)\n3. [Why rewrite pull requests?](#why-rewrite-pull-requests)\n4. [Keep in sync with upstream](#keep-in-sync-with-upstream)\n5. [Commit messages](#commit-messages)\n6. [If you mess up, don't panic](#if-you-mess-up-dont-panic)\n7. [Edit a single commit](#edit-a-single-commit)\n8. [Reorder commits](#reorder-commits)\n9. [Squash commits](#squash-commits)\n10. [Split commits](#split-commits)\n\n### About\n\nThis will be a random collection of git tips and tricks from the\ntrenches.  It will explain the nitty gritty of rewriting branch\nhistory to make clean pull requests.\n\nIt's not a substitute for reading the git documentation.  The reader\nis supposed to know the basics of git, and to be able to look up\ndetails about git commands in the manual pages.\n\n### A Little Bit Of Background\n\nGit was made by Linus Torvalds for managing Linux source code.  I\nthink it helps to understand how it was managed before Linus used\nsource control.  There were releases: tarballs which snapshotted the\nsource tree.  And there were patch series: a series of diffs building\non each others, usually posted to a mailing list.\n\nThe tarball snapshots map quite well to git version history.  In some\ncontexts, a git commit can be viewed as just a plain snapshot of the\nentire source tree.  When you check out a commit, it's like deleting\nall files and extract a tarball.\n\nA patch series is similar to a pull request.  In this view, it's all\nabout the diffs.  Each diff in the series is requred to make one\nlogical, atomic change.  When a new Linux version was released, you\nwere required to redo the patch series by applying it to the new\nversion and update any mismatches.  This is exactly like rebasing.\n\n### Why rewrite pull requests?\n\nIt's not just for fun, rewriting your pull request have actual\nbenefits.\n\n- It's easier to review a pull request that consists of small atomic\n  commits.  Perhaps more importantly, sometimes a a bug appears and\n  someone else has to go back and look at your commits to understand\n  their intent.\n\n- If branch goes out of sync with the upstream master, rebasing it\n  will make it possible to a fast-forward merge.  This makes for a\n  linear history which is easier to understand than a history which\n  branches and joins in several parallel arcs.\n\n- Sometimes a change needs to be backed out.  If the commit does\n  several unrelated things, a simple revert operation removes\n  everything.\n\n- It's generally accepted that code should be clean and readable.\n  Just extend the notion to the time dimension.  Changes should be\n  readable too.  Avoid spaghetti history like you would spaghetti\n  code.\n\n### Keep in sync with upstream\n\nI recommend never adding any commits to the master branch.  Always\nmake a new branch for new features or bug fixes.\n\nBefore you make a new branch, it's a good idea to update your\nrepository from upstream.  Do a `git fetch` to bring in new commits,\ncheck out your local master branch, and the `git merge --ff-only\norigin/master`.\n\nSometimes, there can be two remote repositories: your own copy, and\nthe upstream repository to which you will post pull requests.  I have\nmy own remote as `origin` and the other I call `upstream`.  I fetch\nfrom upstream to update the local master branch, and then I push this\nto `origin`.  This way, my local and remote mater always tracks the\nupstream.\n\n### Commit messages\n\nI'll just copy from the \"git commit\" man page:\n\n\u003e it’s a good idea to begin the commit message with a single short\n\u003e (less than 50 character) line summarizing the change, followed by a\n\u003e blank line and then a more thorough description.\n\n### If you mess up, don't panic\n\nSometimes you're in the middle of a messy rewrite operation and you\nfeel things aren't coming together like you wish.  Don't worry, most\nof the time you can type `git rebase --abort` to reset back to before\nthe operation.  Reconsider your plan and start over.\n\nIf you completed the rebase (or other operation) and have regrets, you\ncan try the reflog.  This is a long log of every commit git recorded.\nType `git reflog` and look at the top of the output.  If you want to\ngo back to a previous good commit FOO, type `git reset --hard FOO`.\n**Warning:** this will overwrite files.  If you have any pending\nchanges that are not committed, they will be lost.\n\n### Edit a single commit\n\nTo update the very latest commit, just stage your changes and type\n`git commit --amend -C HEAD`.  Amending means to add changes to an\nexisting commit, and `-C HEAD` is used to keep the commit message as\nis.\n\nTo update another commit, do `git rebase -i FOO~`, where FOO is that\ncommit.  It can be a hexadecimal commit ID, or a revision like\n`HEAD~3` to select a commit relative to the current head.  This will\nbring up your editor with text like this, plus some help text:\n\n```\npick 1234567 Commit 1.\npick 89abcde Commit 2.\npick 6c437ee Commit 3.\n```\n\nOn the line indicating the commit you want to edit, change `pick` to\n`edit`.  When you exit the editor, git will start a rebase operation\nand stop at that commit.  Now you can amend the commit like described\nabove.  When done, type `git rebase --continue`.\n\n### Reorder commits\n\nThis is easy with interactive rebasing.  Type `git rebase -i master`.\nThis will offer up all commits on your branch:\n\n```\npick 1234567 Commit 1.\npick 89abcde Commit 2.\npick 6c437ee Commit 3.\n```\n\nThis is the Swiss army knife of git.  Each line is a command in git's\nspecial rebase command language.  Each command will be applied in\ntop-down order to the base commit of the rebase, `master` in this\nexample.  Here we see `pick` which just adds a commit to the branch.\nTo reorder the commits, just reorder the lines as you see fit.  Then\nsave the file and exit the editor.\n\nIf the commits overlap, there will be merge conflicts.  Git will\nannounce this and stop for you to fix the conflict.  To do this, you\nedit the files and stage them.  To proceed with the rebase, type `git\nrebase --continue`.\n\n### Squash commits\n\nMerging two or more commits into one is called \"squashing\".  This can\nalso be done with `rebase -i`.  If, say, commit 3 is to be squashed\ninto commit 1, edit the text to say\n\n```\npick 1234567 Commit 1.\nsquash 6c437ee Commit 3.\npick 89abcde Commit 2.\n```\n\nWhen git has finished, there will only be commit 1 and commit 3 left,\nbut the first will include the changes from commit 2.\n\nYou will have the option of editing the commit message, merging text\nfrom both commits.  If this is not necessary, you can use `fixup`\ninstead of `squash`.  The commit message of the fixup commit will be\ndiscarded.\n\n### Split commits\n\nSometimes you make a commit and later want to split it in two.  If you\nwant to split commit FOO, do an interactive rebase against the the\ncommit two before it: `git rebase -i FOO~2`.  Your editor will display\nthe commit immediately before FOO at the top, then FOO, and following\ncommits if any:\n\n```\npick QUUX Commit quux.\npick FOO Commit foo.\npick BAR Commit bar.\npick BAZ Commit baz.\n```\n\nEdit this to look like\n\n```\nedit QUUX Commit quux.\npick FOO Commit foo.\npick BAR Commit bar.\npick BAZ Commit baz.\n```\n\nThis instructs git we want to make a change to a commit.  When you\nexit the editor, git will stop at commit QUUX and let you edit the\nfiles.  Note at this point we're immediately before FOO which we want\nto split.\n\nNow type `git checkout -p FOO` to make a **partial** check out.  If\nyou want just one particular file, type `git checkout -p FOO --\nfilename`.  Git will present you with a series of questions whether\nyou want a particular diff applied or not.  Answer `y` or `n` as\nappropriate, or `s` to split a diff in even smaller parts.\n\nWhen this is finished, you will have staged the changes.  Commit this,\nand continue the rebase operation.  Git will see that FOO already has\nthe changes you split off, so it will not complain.\n\n### Move a change to an earlier commit\n\nSometimes you commit some changes, and later want to move some change\nto an earlier commit instead.  Doing this is similar to splitting a\ncommit described in the previous section.\n\nDo an interactive rebase against the the commit before the one you\nwant to add to: `git rebase -i FOO~1`.  Your editor will display this:\n\n```\npick FOO Commit foo.\npick BAR Commit bar.\npick BAZ Commit baz.\n```\n\nIf you want to move something from BAZ to FOO, instruct git you want\nto edit FOO:\n\n```\nedit FOO Commit foo.\npick BAR Commit bar.\npick BAZ Commit baz.\n```\n\nExit the editor.  Git will stop right after FOO and allow you to do\nedits.  Now type `git checkout -p BAZ`.  Like in *\"Split commits\"*\nabove, you can pick and choose changes.  Say `y` those you want.  When\ndone, your changes are in the staging area.  Now amend FOO: `git\ncommit --amend -C HEAD`.  Continue and finish the rebase.\n\n### Update your pull request\n\nWith GitHub or GitLab, you can just do `git push -f` to forcibly push\nyour branch and update the pull request.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsbrinkhoff%2Ffearless-git","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flarsbrinkhoff%2Ffearless-git","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flarsbrinkhoff%2Ffearless-git/lists"}