CINXE.COM

Git - Rewriting History

<!DOCTYPE html> <html lang="en"> <head> <meta charset='utf-8'> <meta content='IE=edge,chrome=1' http-equiv='X-UA-Compatible'> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Git - Rewriting History</title> <link href="/favicon.ico" rel='shortcut icon' type='image/x-icon'> <link rel="stylesheet" href="/application.min.css"> <script src="/js/modernizr.js"></script> <script src="/js/modernize.js"></script> </head> <body id="documentation"> <div class="inner"> <header> <a href="/"><img src="/images/logo@2x.png" width="110" height="46" alt="Git" /></a> <span id="tagline"></span> <script type="text/javascript"> const taglines = [ "fast-version-control", "everything-is-local", "distributed-even-if-your-workflow-isnt", "local-branching-on-the-cheap", "distributed-is-the-new-centralized" ]; var tagline = taglines[Math.floor(Math.random() * taglines.length)]; document.getElementById('tagline').innerHTML = '--' + tagline; </script> <form id="search" action="/search/results"> <input id="search-text" name="search" placeholder="Type / to search entire site…" autocomplete="off" type="text" /> </form> <div id="search-results"></div> </header> </div> <div class="inner"> <div id="content-wrapper"> <div tabindex="1" class="sidebar-btn"></div> <aside class="sidebar" id="sidebar"> <nav> <ul> <li> <a href="/about">About</a> <ul> </ul> </li> <li> <a href="/doc" class="active">Documentation</a> <ul class="expanded"> <li> <a href="/docs">Reference</a> </li> <li> <a href="/book" class="active">Book</a> </li> <li> <a href="/videos">Videos</a> </li> <li> <a href="/doc/ext">External Links</a> </li> </ul> </li> <li> <a href="/downloads">Downloads</a> <ul > <li> <a href="/downloads/guis">GUI Clients</a> </li> <li> <a href="/downloads/logos">Logos</a> </li> </ul> </li> <li> <a href="/community">Community</a> </li> </ul> <hr class="sidebar"> <p> This book is available in <a href="/book/en/v2/Git-Tools-Rewriting-History">English</a>. </p> <p> Full translation available in <table> <tr><td><a href="/book/az/v2/Git-Al%c9%99tl%c9%99ri-Tarixi-Yenid%c9%99n-Yazmaq">azərbaycan dili</a>,</td></tr> <tr><td><a href="/book/bg">български език</a>,</td></tr> <tr><td><a href="/book/de/v2/Git-Tools-Den-Verlauf-umschreiben">Deutsch</a>,</td></tr> <tr><td><a href="/book/es/v2/Herramientas-de-Git-Reescribiendo-la-Historia">Español</a>,</td></tr> <tr><td><a href="/book/fr/v2/Utilitaires-Git-R%c3%a9%c3%a9crire-l%e2%80%99historique">Français</a>,</td></tr> <tr><td><a href="/book/gr">Ελληνικά</a>,</td></tr> <tr><td><a href="/book/ja/v2/Git-%e3%81%ae%e3%81%95%e3%81%be%e3%81%96%e3%81%be%e3%81%aa%e3%83%84%e3%83%bc%e3%83%ab-%e6%ad%b4%e5%8f%b2%e3%81%ae%e6%9b%b8%e3%81%8d%e6%8f%9b%e3%81%88">日本語</a>,</td></tr> <tr><td><a href="/book/ko/v2/Git-%eb%8f%84%ea%b5%ac-%ed%9e%88%ec%8a%a4%ed%86%a0%eb%a6%ac-%eb%8b%a8%ec%9e%a5%ed%95%98%ea%b8%b0">한국어</a>,</td></tr> <tr><td><a href="/book/nl/v2/Git-Tools-Geschiedenis-herschrijven">Nederlands</a>,</td></tr> <tr><td><a href="/book/ru/v2/%d0%98%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d1%8b-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d0%b8">Русский</a>,</td></tr> <tr><td><a href="/book/sl/v2/Orodja-Git-Prepisovanje-zgodovine">Slovenščina</a>,</td></tr> <tr><td><a href="/book/tl/v2/Mga-Git-na-Kasangkapan-Pagsulat-muli-ng-Kasaysayan">Tagalog</a>,</td></tr> <tr><td><a href="/book/uk/v2/%d0%86%d0%bd%d1%81%d1%82%d1%80%d1%83%d0%bc%d0%b5%d0%bd%d1%82%d0%b8-Git-%d0%9f%d0%b5%d1%80%d0%b5%d0%bf%d0%b8%d1%81%d1%83%d0%b2%d0%b0%d0%bd%d0%bd%d1%8f-%d1%96%d1%81%d1%82%d0%be%d1%80%d1%96%d1%97">Українська</a></td></tr> <tr><td><a href="/book/zh/v2/Git-%e5%b7%a5%e5%85%b7-%e9%87%8d%e5%86%99%e5%8e%86%e5%8f%b2">简体中文</a>,</td></tr> </table> </p> <p> Partial translations available in <table> <tr><td><a href="/book/cs/v2/Git-Tools-Rewriting-History">Čeština</a>,</td></tr> <tr><td><a href="/book/mk/v2/Git-%d0%90%d0%bb%d0%b0%d1%82%d0%ba%d0%b8-Rewriting-History">Македонски</a>,</td></tr> <tr><td><a href="/book/pl/v2/Narz%c4%99dzia-Gita-Przepisywanie-historii">Polski</a>,</td></tr> <tr><td><a href="/book/sr/v2/%d0%93%d0%b8%d1%82-%d0%b0%d0%bb%d0%b0%d1%82%d0%b8-%d0%9f%d0%be%d0%bd%d0%be%d0%b2%d0%bd%d0%be-%d0%b8%d1%81%d0%bf%d0%b8%d1%81%d0%b8%d0%b2%d0%b0%d1%9a%d0%b5-%d0%b8%d1%81%d1%82%d0%be%d1%80%d0%b8%d1%98%d0%b5">Српски</a>,</td></tr> <tr><td><a href="/book/uz/v2/Git-Tools-Rewriting-History">Ўзбекча</a>,</td></tr> <tr><td><a href="/book/zh-tw/v2/Git-%e5%b7%a5%e5%85%b7-Rewriting-History">繁體中文</a>,</td></tr> </table> </p> <p> Translations started for <table> <tr><td><a href="/book/be/v2/Git-Tools-Rewriting-History">Беларуская</a>,</td></tr> <tr><td><a href="/book/fa/v2/Git-Tools-Rewriting-History" dir="rtl">فارسی</a>,</td></tr> <tr><td><a href="/book/id/v2/Git-Tools-Rewriting-History">Indonesian</a>,</td></tr> <tr><td><a href="/book/it/v2/Git-Tools-Rewriting-History">Italiano</a>,</td></tr> <tr><td><a href="/book/ms/v2/Git-Tools-Rewriting-History">Bahasa Melayu</a>,</td></tr> <tr><td><a href="/book/pt-br/v2/Git-Tools-Rewriting-History">Português (Brasil)</a>,</td></tr> <tr><td><a href="/book/pt-pt/v2/Ferramentas-do-Git-Rewriting-History">Português (Portugal)</a>,</td></tr> <tr><td><a href="/book/sv/v2/Git-Tools-Rewriting-History">Svenska</a>,</td></tr> <tr><td><a href="/book/tr/v2/Git-Ara%c3%a7lar%c4%b1-Ge%c3%a7mi%c5%9fi-Yeniden-Yazma">Türkçe</a>.</td></tr> </table> </p> <hr class="sidebar"/> <p> The source of this book is <a href="https://github.com/progit/progit2">hosted on GitHub.</a></br> Patches, suggestions and comments are welcome. </p> </nav> </aside> <div id="content"> <div id="book-chapters"> <a class="dropdown-trigger" id="book-chapters-trigger" data-panel-id="chapters-dropdown" href="#">Chapters ▾</a> <div class='dropdown-panel' id='chapters-dropdown'> <div class='three-column'> <div class="column-left"> <ol class='book-toc'> <li class='chapter'> <h2>1. <a href="/book/en/v2/Getting-Started-About-Version-Control">Getting Started</a></h2> <ol> <li> 1.1 <a href="/book/en/v2/Getting-Started-About-Version-Control">About Version Control</a> </li> <li> 1.2 <a href="/book/en/v2/Getting-Started-A-Short-History-of-Git">A Short History of Git</a> </li> <li> 1.3 <a href="/book/en/v2/Getting-Started-What-is-Git%3F">What is Git?</a> </li> <li> 1.4 <a href="/book/en/v2/Getting-Started-The-Command-Line">The Command Line</a> </li> <li> 1.5 <a href="/book/en/v2/Getting-Started-Installing-Git">Installing Git</a> </li> <li> 1.6 <a href="/book/en/v2/Getting-Started-First-Time-Git-Setup">First-Time Git Setup</a> </li> <li> 1.7 <a href="/book/en/v2/Getting-Started-Getting-Help">Getting Help</a> </li> <li> 1.8 <a href="/book/en/v2/Getting-Started-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>2. <a href="/book/en/v2/Git-Basics-Getting-a-Git-Repository">Git Basics</a></h2> <ol> <li> 2.1 <a href="/book/en/v2/Git-Basics-Getting-a-Git-Repository">Getting a Git Repository</a> </li> <li> 2.2 <a href="/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository">Recording Changes to the Repository</a> </li> <li> 2.3 <a href="/book/en/v2/Git-Basics-Viewing-the-Commit-History">Viewing the Commit History</a> </li> <li> 2.4 <a href="/book/en/v2/Git-Basics-Undoing-Things">Undoing Things</a> </li> <li> 2.5 <a href="/book/en/v2/Git-Basics-Working-with-Remotes">Working with Remotes</a> </li> <li> 2.6 <a href="/book/en/v2/Git-Basics-Tagging">Tagging</a> </li> <li> 2.7 <a href="/book/en/v2/Git-Basics-Git-Aliases">Git Aliases</a> </li> <li> 2.8 <a href="/book/en/v2/Git-Basics-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>3. <a href="/book/en/v2/Git-Branching-Branches-in-a-Nutshell">Git Branching</a></h2> <ol> <li> 3.1 <a href="/book/en/v2/Git-Branching-Branches-in-a-Nutshell">Branches in a Nutshell</a> </li> <li> 3.2 <a href="/book/en/v2/Git-Branching-Basic-Branching-and-Merging">Basic Branching and Merging</a> </li> <li> 3.3 <a href="/book/en/v2/Git-Branching-Branch-Management">Branch Management</a> </li> <li> 3.4 <a href="/book/en/v2/Git-Branching-Branching-Workflows">Branching Workflows</a> </li> <li> 3.5 <a href="/book/en/v2/Git-Branching-Remote-Branches">Remote Branches</a> </li> <li> 3.6 <a href="/book/en/v2/Git-Branching-Rebasing">Rebasing</a> </li> <li> 3.7 <a href="/book/en/v2/Git-Branching-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>4. <a href="/book/en/v2/Git-on-the-Server-The-Protocols">Git on the Server</a></h2> <ol> <li> 4.1 <a href="/book/en/v2/Git-on-the-Server-The-Protocols">The Protocols</a> </li> <li> 4.2 <a href="/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server">Getting Git on a Server</a> </li> <li> 4.3 <a href="/book/en/v2/Git-on-the-Server-Generating-Your-SSH-Public-Key">Generating Your SSH Public Key</a> </li> <li> 4.4 <a href="/book/en/v2/Git-on-the-Server-Setting-Up-the-Server">Setting Up the Server</a> </li> <li> 4.5 <a href="/book/en/v2/Git-on-the-Server-Git-Daemon">Git Daemon</a> </li> <li> 4.6 <a href="/book/en/v2/Git-on-the-Server-Smart-HTTP">Smart HTTP</a> </li> <li> 4.7 <a href="/book/en/v2/Git-on-the-Server-GitWeb">GitWeb</a> </li> <li> 4.8 <a href="/book/en/v2/Git-on-the-Server-GitLab">GitLab</a> </li> <li> 4.9 <a href="/book/en/v2/Git-on-the-Server-Third-Party-Hosted-Options">Third Party Hosted Options</a> </li> <li> 4.10 <a href="/book/en/v2/Git-on-the-Server-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>5. <a href="/book/en/v2/Distributed-Git-Distributed-Workflows">Distributed Git</a></h2> <ol> <li> 5.1 <a href="/book/en/v2/Distributed-Git-Distributed-Workflows">Distributed Workflows</a> </li> <li> 5.2 <a href="/book/en/v2/Distributed-Git-Contributing-to-a-Project">Contributing to a Project</a> </li> <li> 5.3 <a href="/book/en/v2/Distributed-Git-Maintaining-a-Project">Maintaining a Project</a> </li> <li> 5.4 <a href="/book/en/v2/Distributed-Git-Summary">Summary</a> </li> </ol> </li> </ol> </div> <div class='column-middle'> <ol class='book-toc'> <li class='chapter'> <h2>6. <a href="/book/en/v2/GitHub-Account-Setup-and-Configuration">GitHub</a></h2> <ol> <li> 6.1 <a href="/book/en/v2/GitHub-Account-Setup-and-Configuration">Account Setup and Configuration</a> </li> <li> 6.2 <a href="/book/en/v2/GitHub-Contributing-to-a-Project">Contributing to a Project</a> </li> <li> 6.3 <a href="/book/en/v2/GitHub-Maintaining-a-Project">Maintaining a Project</a> </li> <li> 6.4 <a href="/book/en/v2/GitHub-Managing-an-organization">Managing an organization</a> </li> <li> 6.5 <a href="/book/en/v2/GitHub-Scripting-GitHub">Scripting GitHub</a> </li> <li> 6.6 <a href="/book/en/v2/GitHub-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>7. <a href="/book/en/v2/Git-Tools-Revision-Selection">Git Tools</a></h2> <ol> <li> 7.1 <a href="/book/en/v2/Git-Tools-Revision-Selection">Revision Selection</a> </li> <li> 7.2 <a href="/book/en/v2/Git-Tools-Interactive-Staging">Interactive Staging</a> </li> <li> 7.3 <a href="/book/en/v2/Git-Tools-Stashing-and-Cleaning">Stashing and Cleaning</a> </li> <li> 7.4 <a href="/book/en/v2/Git-Tools-Signing-Your-Work">Signing Your Work</a> </li> <li> 7.5 <a href="/book/en/v2/Git-Tools-Searching">Searching</a> </li> <li> 7.6 <a href="/book/en/v2/Git-Tools-Rewriting-History" class="active">Rewriting History</a> </li> <li> 7.7 <a href="/book/en/v2/Git-Tools-Reset-Demystified">Reset Demystified</a> </li> <li> 7.8 <a href="/book/en/v2/Git-Tools-Advanced-Merging">Advanced Merging</a> </li> <li> 7.9 <a href="/book/en/v2/Git-Tools-Rerere">Rerere</a> </li> <li> 7.10 <a href="/book/en/v2/Git-Tools-Debugging-with-Git">Debugging with Git</a> </li> <li> 7.11 <a href="/book/en/v2/Git-Tools-Submodules">Submodules</a> </li> <li> 7.12 <a href="/book/en/v2/Git-Tools-Bundling">Bundling</a> </li> <li> 7.13 <a href="/book/en/v2/Git-Tools-Replace">Replace</a> </li> <li> 7.14 <a href="/book/en/v2/Git-Tools-Credential-Storage">Credential Storage</a> </li> <li> 7.15 <a href="/book/en/v2/Git-Tools-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>8. <a href="/book/en/v2/Customizing-Git-Git-Configuration">Customizing Git</a></h2> <ol> <li> 8.1 <a href="/book/en/v2/Customizing-Git-Git-Configuration">Git Configuration</a> </li> <li> 8.2 <a href="/book/en/v2/Customizing-Git-Git-Attributes">Git Attributes</a> </li> <li> 8.3 <a href="/book/en/v2/Customizing-Git-Git-Hooks">Git Hooks</a> </li> <li> 8.4 <a href="/book/en/v2/Customizing-Git-An-Example-Git-Enforced-Policy">An Example Git-Enforced Policy</a> </li> <li> 8.5 <a href="/book/en/v2/Customizing-Git-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>9. <a href="/book/en/v2/Git-and-Other-Systems-Git-as-a-Client">Git and Other Systems</a></h2> <ol> <li> 9.1 <a href="/book/en/v2/Git-and-Other-Systems-Git-as-a-Client">Git as a Client</a> </li> <li> 9.2 <a href="/book/en/v2/Git-and-Other-Systems-Migrating-to-Git">Migrating to Git</a> </li> <li> 9.3 <a href="/book/en/v2/Git-and-Other-Systems-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>10. <a href="/book/en/v2/Git-Internals-Plumbing-and-Porcelain">Git Internals</a></h2> <ol> <li> 10.1 <a href="/book/en/v2/Git-Internals-Plumbing-and-Porcelain">Plumbing and Porcelain</a> </li> <li> 10.2 <a href="/book/en/v2/Git-Internals-Git-Objects">Git Objects</a> </li> <li> 10.3 <a href="/book/en/v2/Git-Internals-Git-References">Git References</a> </li> <li> 10.4 <a href="/book/en/v2/Git-Internals-Packfiles">Packfiles</a> </li> <li> 10.5 <a href="/book/en/v2/Git-Internals-The-Refspec">The Refspec</a> </li> <li> 10.6 <a href="/book/en/v2/Git-Internals-Transfer-Protocols">Transfer Protocols</a> </li> <li> 10.7 <a href="/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery">Maintenance and Data Recovery</a> </li> <li> 10.8 <a href="/book/en/v2/Git-Internals-Environment-Variables">Environment Variables</a> </li> <li> 10.9 <a href="/book/en/v2/Git-Internals-Summary">Summary</a> </li> </ol> </li> </ol> </div> <div class='column-right'> <ol class='book-toc'> <li class='chapter'> <h2>A1. <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces">Appendix A: Git in Other Environments</a></h2> <ol> <li> A1.1 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Graphical-Interfaces">Graphical Interfaces</a> </li> <li> A1.2 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio">Git in Visual Studio</a> </li> <li> A1.3 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Visual-Studio-Code">Git in Visual Studio Code</a> </li> <li> A1.4 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-IntelliJ-/-PyCharm-/-WebStorm-/-PhpStorm-/-RubyMine">Git in IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine</a> </li> <li> A1.5 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Sublime-Text">Git in Sublime Text</a> </li> <li> A1.6 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Bash">Git in Bash</a> </li> <li> A1.7 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-Zsh">Git in Zsh</a> </li> <li> A1.8 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Git-in-PowerShell">Git in PowerShell</a> </li> <li> A1.9 <a href="/book/en/v2/Appendix-A:-Git-in-Other-Environments-Summary">Summary</a> </li> </ol> </li> <li class='chapter'> <h2>A2. <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git">Appendix B: Embedding Git in your Applications</a></h2> <ol> <li> A2.1 <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Command-line-Git">Command-line Git</a> </li> <li> A2.2 <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Libgit2">Libgit2</a> </li> <li> A2.3 <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-JGit">JGit</a> </li> <li> A2.4 <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-go-git">go-git</a> </li> <li> A2.5 <a href="/book/en/v2/Appendix-B:-Embedding-Git-in-your-Applications-Dulwich">Dulwich</a> </li> </ol> </li> <li class='chapter'> <h2>A3. <a href="/book/en/v2/Appendix-C:-Git-Commands-Setup-and-Config">Appendix C: Git Commands</a></h2> <ol> <li> A3.1 <a href="/book/en/v2/Appendix-C:-Git-Commands-Setup-and-Config">Setup and Config</a> </li> <li> A3.2 <a href="/book/en/v2/Appendix-C:-Git-Commands-Getting-and-Creating-Projects">Getting and Creating Projects</a> </li> <li> A3.3 <a href="/book/en/v2/Appendix-C:-Git-Commands-Basic-Snapshotting">Basic Snapshotting</a> </li> <li> A3.4 <a href="/book/en/v2/Appendix-C:-Git-Commands-Branching-and-Merging">Branching and Merging</a> </li> <li> A3.5 <a href="/book/en/v2/Appendix-C:-Git-Commands-Sharing-and-Updating-Projects">Sharing and Updating Projects</a> </li> <li> A3.6 <a href="/book/en/v2/Appendix-C:-Git-Commands-Inspection-and-Comparison">Inspection and Comparison</a> </li> <li> A3.7 <a href="/book/en/v2/Appendix-C:-Git-Commands-Debugging">Debugging</a> </li> <li> A3.8 <a href="/book/en/v2/Appendix-C:-Git-Commands-Patching">Patching</a> </li> <li> A3.9 <a href="/book/en/v2/Appendix-C:-Git-Commands-Email">Email</a> </li> <li> A3.10 <a href="/book/en/v2/Appendix-C:-Git-Commands-External-Systems">External Systems</a> </li> <li> A3.11 <a href="/book/en/v2/Appendix-C:-Git-Commands-Administration">Administration</a> </li> <li> A3.12 <a href="/book/en/v2/Appendix-C:-Git-Commands-Plumbing-Commands">Plumbing Commands</a> </li> </ol> </li> </ol> </div> </div> </div> <span class="light" id="edition"> 2nd Edition </span> </div> <div id="main" data-pagefind-filter="category:book" data-pagefind-meta="category:Book" data-pagefind-weight="0.05" data-pagefind-body class="book edition2"> <h1>7.6 Git Tools - Rewriting History</h1> <div> <h2 id="_rewriting_history">Rewriting History</h2> <div class="paragraph"> <p>Many times, when working with Git, you may want to revise your local commit history. One of the great things about Git is that it allows you to make decisions at the last possible moment. You can decide what files go into which commits right before you commit with the staging area, you can decide that you didn’t mean to be working on something yet with <code>git stash</code>, and you can rewrite commits that already happened so they look like they happened in a different way. This can involve changing the order of the commits, changing messages or modifying files in a commit, squashing together or splitting apart commits, or removing commits entirely — all before you share your work with others.</p> </div> <div class="paragraph"> <p>In this section, you’ll see how to accomplish these tasks so that you can make your commit history look the way you want before you share it with others.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Note</div> </td> <td class="content"> <div class="title">Don’t push your work until you’re happy with it</div> <div class="paragraph"> <p>One of the cardinal rules of Git is that, since so much work is local within your clone, you have a great deal of freedom to rewrite your history <em>locally</em>. However, once you push your work, it is a different story entirely, and you should consider pushed work as final unless you have good reason to change it. In short, you should avoid pushing your work until you’re happy with it and ready to share it with the rest of the world.</p> </div> </td> </tr> </table> </div> <div class="sect3"> <h3 id="_git_amend">Changing the Last Commit</h3> <div class="paragraph"> <p>Changing your most recent commit is probably the most common rewriting of history that you’ll do. You’ll often want to do two basic things to your last commit: simply change the commit message, or change the actual content of the commit by adding, removing and modifying files.</p> </div> <div class="paragraph"> <p>If you simply want to modify your last commit message, that’s easy:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit --amend</code></pre> </div> </div> <div class="paragraph"> <p>The command above loads the previous commit message into an editor session, where you can make changes to the message, save those changes and exit. When you save and close the editor, the editor writes a new commit containing that updated commit message and makes it your new last commit.</p> </div> <div class="paragraph"> <p>If, on the other hand, you want to change the actual <em>content</em> of your last commit, the process works basically the same way — first make the changes you think you forgot, stage those changes, and the subsequent <code>git commit --amend</code> <em>replaces</em> that last commit with your new, improved commit.</p> </div> <div class="paragraph"> <p>You need to be careful with this technique because amending changes the SHA-1 of the commit. It’s like a very small rebase — don’t amend your last commit if you’ve already pushed it.</p> </div> <div class="admonitionblock tip"> <table> <tr> <td class="icon"> <div class="title">Tip</div> </td> <td class="content"> <div class="title">An amended commit may (or may not) need an amended commit message</div> <div class="paragraph"> <p>When you amend a commit, you have the opportunity to change both the commit message and the content of the commit. If you amend the content of the commit substantially, you should almost certainly update the commit message to reflect that amended content.</p> </div> <div class="paragraph"> <p>On the other hand, if your amendments are suitably trivial (fixing a silly typo or adding a file you forgot to stage) such that the earlier commit message is just fine, you can simply make the changes, stage them, and avoid the unnecessary editor session entirely with:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit --amend --no-edit</code></pre> </div> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h3 id="_changing_multiple">Changing Multiple Commit Messages</h3> <div class="paragraph"> <p>To modify a commit that is farther back in your history, you must move to more complex tools. Git doesn’t have a modify-history tool, but you can use the rebase tool to rebase a series of commits onto the HEAD that they were originally based on instead of moving them to another one. With the interactive rebase tool, you can then stop after each commit you want to modify and change the message, add files, or do whatever you wish. You can run rebase interactively by adding the <code>-i</code> option to <code>git rebase</code>. You must indicate how far back you want to rewrite commits by telling the command which commit to rebase onto.</p> </div> <div class="paragraph"> <p>For example, if you want to change the last three commit messages, or any of the commit messages in that group, you supply as an argument to <code>git rebase -i</code> the parent of the last commit you want to edit, which is <code>HEAD~2^</code> or <code>HEAD~3</code>. It may be easier to remember the <code>~3</code> because you’re trying to edit the last three commits, but keep in mind that you’re actually designating four commits ago, the parent of the last commit you want to edit:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase -i HEAD~3</code></pre> </div> </div> <div class="paragraph"> <p>Remember again that this is a rebasing command — every commit in the range <code>HEAD~3..HEAD</code> with a changed message <em>and all of its descendants</em> will be rewritten. Don’t include any commit you’ve already pushed to a central server — doing so will confuse other developers by providing an alternate version of the same change.</p> </div> <div class="paragraph"> <p>Running this command gives you a list of commits in your text editor that looks something like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick f7f3f6d Change my name a bit pick 310154e Update README formatting and add blame pick a5f4a0d Add cat-file # Rebase 710f0f8..a5f4a0d onto 710f0f8 # # Commands: # p, pick &lt;commit&gt; = use commit # r, reword &lt;commit&gt; = use commit, but edit the commit message # e, edit &lt;commit&gt; = use commit, but stop for amending # s, squash &lt;commit&gt; = use commit, but meld into previous commit # f, fixup &lt;commit&gt; = like "squash", but discard this commit's log message # x, exec &lt;command&gt; = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop &lt;commit&gt; = remove commit # l, label &lt;label&gt; = label current HEAD with a name # t, reset &lt;label&gt; = reset HEAD to a label # m, merge [-C &lt;commit&gt; | -c &lt;commit&gt;] &lt;label&gt; [# &lt;oneline&gt;] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c &lt;commit&gt; to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out</code></pre> </div> </div> <div class="paragraph"> <p>It’s important to note that these commits are listed in the opposite order than you normally see them using the <code>log</code> command. If you run a <code>log</code>, you see something like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log --pretty=format:"%h %s" HEAD~3..HEAD a5f4a0d Add cat-file 310154e Update README formatting and add blame f7f3f6d Change my name a bit</code></pre> </div> </div> <div class="paragraph"> <p>Notice the reverse order. The interactive rebase gives you a script that it’s going to run. It will start at the commit you specify on the command line (<code>HEAD~3</code>) and replay the changes introduced in each of these commits from top to bottom. It lists the oldest at the top, rather than the newest, because that’s the first one it will replay.</p> </div> <div class="paragraph"> <p>You need to edit the script so that it stops at the commit you want to edit. To do so, change the word “pick” to the word “edit” for each of the commits you want the script to stop after. For example, to modify only the third commit message, you change the file to look like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">edit f7f3f6d Change my name a bit pick 310154e Update README formatting and add blame pick a5f4a0d Add cat-file</code></pre> </div> </div> <div class="paragraph"> <p>When you save and exit the editor, Git rewinds you back to the last commit in that list and drops you on the command line with the following message:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase -i HEAD~3 Stopped at f7f3f6d... Change my name a bit You can amend the commit now, with git commit --amend Once you're satisfied with your changes, run git rebase --continue</code></pre> </div> </div> <div class="paragraph"> <p>These instructions tell you exactly what to do. Type:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git commit --amend</code></pre> </div> </div> <div class="paragraph"> <p>Change the commit message, and exit the editor. Then, run:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git rebase --continue</code></pre> </div> </div> <div class="paragraph"> <p>This command will apply the other two commits automatically, and then you’re done. If you change <code>pick</code> to <code>edit</code> on more lines, you can repeat these steps for each commit you change to <code>edit</code>. Each time, Git will stop, let you amend the commit, and continue when you’re finished.</p> </div> </div> <div class="sect3"> <h3 id="_reordering_commits">Reordering Commits</h3> <div class="paragraph"> <p>You can also use interactive rebases to reorder or remove commits entirely. If you want to remove the “Add cat-file” commit and change the order in which the other two commits are introduced, you can change the rebase script from this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick f7f3f6d Change my name a bit pick 310154e Update README formatting and add blame pick a5f4a0d Add cat-file</code></pre> </div> </div> <div class="paragraph"> <p>to this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick 310154e Update README formatting and add blame pick f7f3f6d Change my name a bit</code></pre> </div> </div> <div class="paragraph"> <p>When you save and exit the editor, Git rewinds your branch to the parent of these commits, applies <code>310154e</code> and then <code>f7f3f6d</code>, and then stops. You effectively change the order of those commits and remove the “Add cat-file” commit completely.</p> </div> </div> <div class="sect3"> <h3 id="_squashing">Squashing Commits</h3> <div class="paragraph"> <p>It’s also possible to take a series of commits and squash them down into a single commit with the interactive rebasing tool. The script puts helpful instructions in the rebase message:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># # Commands: # p, pick &lt;commit&gt; = use commit # r, reword &lt;commit&gt; = use commit, but edit the commit message # e, edit &lt;commit&gt; = use commit, but stop for amending # s, squash &lt;commit&gt; = use commit, but meld into previous commit # f, fixup &lt;commit&gt; = like "squash", but discard this commit's log message # x, exec &lt;command&gt; = run command (the rest of the line) using shell # b, break = stop here (continue rebase later with 'git rebase --continue') # d, drop &lt;commit&gt; = remove commit # l, label &lt;label&gt; = label current HEAD with a name # t, reset &lt;label&gt; = reset HEAD to a label # m, merge [-C &lt;commit&gt; | -c &lt;commit&gt;] &lt;label&gt; [# &lt;oneline&gt;] # . create a merge commit using the original merge commit's # . message (or the oneline, if no original merge commit was # . specified). Use -c &lt;commit&gt; to reword the commit message. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out</code></pre> </div> </div> <div class="paragraph"> <p>If, instead of “pick” or “edit”, you specify “squash”, Git applies both that change and the change directly before it and makes you merge the commit messages together. So, if you want to make a single commit from these three commits, you make the script look like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick f7f3f6d Change my name a bit squash 310154e Update README formatting and add blame squash a5f4a0d Add cat-file</code></pre> </div> </div> <div class="paragraph"> <p>When you save and exit the editor, Git applies all three changes and then puts you back into the editor to merge the three commit messages:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console"># This is a combination of 3 commits. # The first commit's message is: Change my name a bit # This is the 2nd commit message: Update README formatting and add blame # This is the 3rd commit message: Add cat-file</code></pre> </div> </div> <div class="paragraph"> <p>When you save that, you have a single commit that introduces the changes of all three previous commits.</p> </div> </div> <div class="sect3"> <h3 id="_splitting_a_commit">Splitting a Commit</h3> <div class="paragraph"> <p>Splitting a commit undoes a commit and then partially stages and commits as many times as commits you want to end up with. For example, suppose you want to split the middle commit of your three commits. Instead of “Update README formatting and add blame”, you want to split it into two commits: “Update README formatting” for the first, and “Add blame” for the second. You can do that in the <code>rebase -i</code> script by changing the instruction on the commit you want to split to “edit”:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick f7f3f6d Change my name a bit edit 310154e Update README formatting and add blame pick a5f4a0d Add cat-file</code></pre> </div> </div> <div class="paragraph"> <p>Then, when the script drops you to the command line, you reset that commit, take the changes that have been reset, and create multiple commits out of them. When you save and exit the editor, Git rewinds to the parent of the first commit in your list, applies the first commit (<code>f7f3f6d</code>), applies the second (<code>310154e</code>), and drops you to the console. There, you can do a mixed reset of that commit with <code>git reset HEAD^</code>, which effectively undoes that commit and leaves the modified files unstaged. Now you can stage and commit files until you have several commits, and run <code>git rebase --continue</code> when you’re done:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git reset HEAD^ $ git add README $ git commit -m 'Update README formatting' $ git add lib/simplegit.rb $ git commit -m 'Add blame' $ git rebase --continue</code></pre> </div> </div> <div class="paragraph"> <p>Git applies the last commit (<code>a5f4a0d</code>) in the script, and your history looks like this:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git log -4 --pretty=format:"%h %s" 1c002dd Add cat-file 9b29157 Add blame 35cfb2b Update README formatting f7f3f6d Change my name a bit</code></pre> </div> </div> <div class="paragraph"> <p>This changes the SHA-1s of the three most recent commits in your list, so make sure no changed commit shows up in that list that you’ve already pushed to a shared repository. Notice that the last commit (<code>f7f3f6d</code>) in the list is unchanged. Despite this commit being shown in the script, because it was marked as “pick” and was applied prior to any rebase changes, Git leaves the commit unmodified.</p> </div> </div> <div class="sect3"> <h3 id="_deleting_a_commit">Deleting a commit</h3> <div class="paragraph"> <p>If you want to get rid of a commit, you can delete it using the <code>rebase -i</code> script. In the list of commits, put the word “drop” before the commit you want to delete (or just delete that line from the rebase script):</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">pick 461cb2a This commit is OK drop 5aecc10 This commit is broken</code></pre> </div> </div> <div class="paragraph"> <p>Because of the way Git builds commit objects, deleting or altering a commit will cause the rewriting of all the commits that follow it. The further back in your repo’s history you go, the more commits will need to be recreated. This can cause lots of merge conflicts if you have many commits later in the sequence that depend on the one you just deleted.</p> </div> <div class="paragraph"> <p>If you get partway through a rebase like this and decide it’s not a good idea, you can always stop. Type <code>git rebase --abort</code>, and your repo will be returned to the state it was in before you started the rebase.</p> </div> <div class="paragraph"> <p>If you finish a rebase and decide it’s not what you want, you can use <code>git reflog</code> to recover an earlier version of your branch. See <a href="/book/en/v2/ch00/_data_recovery">Data Recovery</a> for more information on the <code>reflog</code> command.</p> </div> <div class="admonitionblock note"> <table> <tr> <td class="icon"> <div class="title">Note</div> </td> <td class="content"> <div class="paragraph"> <p>Drew DeVault made a practical hands-on guide with exercises to learn how to use <code>git rebase</code>. You can find it at: <a href="https://git-rebase.io/" class="bare" target="_blank" rel="noopener">https://git-rebase.io/</a></p> </div> </td> </tr> </table> </div> </div> <div class="sect3"> <h3 id="_the_nuclear_option_filter_branch">The Nuclear Option: filter-branch</h3> <div class="paragraph"> <p>There is another history-rewriting option that you can use if you need to rewrite a larger number of commits in some scriptable way — for instance, changing your email address globally or removing a file from every commit. The command is <code>filter-branch</code>, and it can rewrite huge swaths of your history, so you probably shouldn’t use it unless your project isn’t yet public and other people haven’t based work off the commits you’re about to rewrite. However, it can be very useful. You’ll learn a few of the common uses so you can get an idea of some of the things it’s capable of.</p> </div> <div class="admonitionblock caution"> <table> <tr> <td class="icon"> <div class="title">Caution</div> </td> <td class="content"> <div class="paragraph"> <p><code>git filter-branch</code> has many pitfalls, and is no longer the recommended way to rewrite history. Instead, consider using <code>git-filter-repo</code>, which is a Python script that does a better job for most applications where you would normally turn to <code>filter-branch</code>. Its documentation and source code can be found at <a href="https://github.com/newren/git-filter-repo" class="bare" target="_blank" rel="noopener">https://github.com/newren/git-filter-repo</a>.</p> </div> </td> </tr> </table> </div> <div class="sect4"> <h4 id="_removing_file_every_commit">Removing a File from Every Commit</h4> <div class="paragraph"> <p>This occurs fairly commonly. Someone accidentally commits a huge binary file with a thoughtless <code>git add .</code>, and you want to remove it everywhere. Perhaps you accidentally committed a file that contained a password, and you want to make your project open source. <code>filter-branch</code> is the tool you probably want to use to scrub your entire history. To remove a file named <code>passwords.txt</code> from your entire history, you can use the <code>--tree-filter</code> option to <code>filter-branch</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21) Ref 'refs/heads/master' was rewritten</code></pre> </div> </div> <div class="paragraph"> <p>The <code>--tree-filter</code> option runs the specified command after each checkout of the project and then recommits the results. In this case, you remove a file called <code>passwords.txt</code> from every snapshot, whether it exists or not. If you want to remove all accidentally committed editor backup files, you can run something like <code>git filter-branch --tree-filter 'rm -f *~' HEAD</code>.</p> </div> <div class="paragraph"> <p>You’ll be able to watch Git rewriting trees and commits and then move the branch pointer at the end. It’s generally a good idea to do this in a testing branch and then hard-reset your <code>master</code> branch after you’ve determined the outcome is what you really want. To run <code>filter-branch</code> on all your branches, you can pass <code>--all</code> to the command.</p> </div> </div> <div class="sect4"> <h4 id="_making_a_subdirectory_the_new_root">Making a Subdirectory the New Root</h4> <div class="paragraph"> <p>Suppose you’ve done an import from another source control system and have subdirectories that make no sense (<code>trunk</code>, <code>tags</code>, and so on). If you want to make the <code>trunk</code> subdirectory be the new project root for every commit, <code>filter-branch</code> can help you do that, too:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git filter-branch --subdirectory-filter trunk HEAD Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12) Ref 'refs/heads/master' was rewritten</code></pre> </div> </div> <div class="paragraph"> <p>Now your new project root is what was in the <code>trunk</code> subdirectory each time. Git will also automatically remove commits that did not affect the subdirectory.</p> </div> </div> <div class="sect4"> <h4 id="_changing_email_addresses_globally">Changing Email Addresses Globally</h4> <div class="paragraph"> <p>Another common case is that you forgot to run <code>git config</code> to set your name and email address before you started working, or perhaps you want to open-source a project at work and change all your work email addresses to your personal address. In any case, you can change email addresses in multiple commits in a batch with <code>filter-branch</code> as well. You need to be careful to change only the email addresses that are yours, so you use <code>--commit-filter</code>:</p> </div> <div class="listingblock"> <div class="content"> <pre class="highlight"><code class="language-console" data-lang="console">$ git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ]; then GIT_AUTHOR_NAME="Scott Chacon"; GIT_AUTHOR_EMAIL="schacon@example.com"; git commit-tree "$@"; else git commit-tree "$@"; fi' HEAD</code></pre> </div> </div> <div class="paragraph"> <p>This goes through and rewrites every commit to have your new address. Because commits contain the SHA-1 values of their parents, this command changes every commit SHA-1 in your history, not just those that have the matching email address.</p> </div> </div> </div> <div id="nav"><a href="/book/en/v2/Git-Tools-Searching">prev</a> | <a href="/book/en/v2/Git-Tools-Reset-Demystified">next</a></div> </div> </div> </div> </div> <footer> <div class="site-source"> <a href="/site">About this site</a><br> Patches, suggestions, and comments are welcome. </div> <div class="sfc-member"> Git is a member of <a href="/sfc">Software Freedom Conservancy</a> </div> </footer> <a href="#top" class="no-js scrollToTop" id="scrollToTop" data-label="Scroll to top"> <img src="/images/icons/chevron-up@2x.png" width="20" height="20" alt="scroll-to-top"/> </a> <script src="/js/jquery-1.7.1.min.js"></script> <script src="/js/jquery-ui-1.8.18.custom.min.js"></script> <script src="/js/jquery.defaultvalue.js"></script> <script src="/js/session.min.js"></script> <script src="/js/application.min.js"></script> </div> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10