<p>Suppose your git history looks like this:</p>

<p>1
2
3
4
5</p>

<p>1–5 are separate revisions. You need to remove 3 while still keeping 1, 2, 4 and 5. How can this be done?</p>

<p>Is there an efficient method when there are hundreds of revisions after the one to be deleted?</p>

[{'answer_id': 37267, 'author': 'garethm', 'author_id': 2219, 'author_profile': 'https://Stackoverflow.com/users/2219', 'pm_score': 7, 'selected': True, 'text': '<p>To combine revision 3 and 4 into a single revision, you can use git rebase. If you want to remove the changes in revision 3, you need to use the edit command in the interactive rebase mode. If you want to combine the changes into a single revision, use squash.</p>\n\n<p>I have successfully used this squash technique, but have never needed to remove a revision before. The git-rebase documentation under "Splitting commits" should hopefully give you enough of an idea to figure it out. (Or someone else might know).</p>\n\n<p>From the <a href="http://git-scm.com/docs/git-rebase" rel="noreferrer">git documentation</a>:</p>\n\n<blockquote>\n<p>Start it with the oldest commit you want to retain as-is:</p>\n\n<blockquote><code>git rebase -i &lt;after-this-commit&gt;</code></blockquote>\n\n<p>An editor will be fired up with all the commits in your current branch (ignoring merge commits), which come after the given commit. You can reorder the commits in this list to your heart\'s content, and you can remove them. The list looks more or less like this:</p>\n\n<blockquote><pre>pick deadbee The oneline of this commit\npick fa1afe1 The oneline of the next commit\n...</pre></blockquote>\n\n<p>The oneline descriptions are purely for your pleasure; git-rebase will not look at them but at the commit names ("deadbee" and "fa1afe1" in this example), so do not delete or edit the names.</p>\n\n<p>By replacing the command "pick" with the command "edit", you can tell git-rebase to stop after applying that commit, so that you can edit the files and/or the commit message, amend the commit, and continue rebasing.</p>\n\n<p>If you want to fold two or more commits into one, replace the command "pick" with "squash" for the second and subsequent commit. If the commits had different authors, it will attribute the squashed commit to the author of the first commit.</p>\n</blockquote>\n'}, {'answer_id': 46186, 'author': 'SpoonMeiser', 'author_id': 1577190, 'author_profile': 'https://Stackoverflow.com/users/1577190', 'pm_score': 5, 'selected': False, 'text': "<p>If all you want to do is remove the changes made in revision 3, you might want to use git revert.</p>\n\n<p>Git revert simply creates a new revision with changes that undo all of the changes in the revision you are reverting.</p>\n\n<p>What this means, is that you retain information about both the unwanted commit, and the commit that removes those changes.</p>\n\n<p>This is probably a lot more friendly if it's at all possible the someone has pulled from your repository in the mean time, since the revert is basically just a standard commit.</p>\n"}, {'answer_id': 3705310, 'author': 'rado', 'author_id': 127388, 'author_profile': 'https://Stackoverflow.com/users/127388', 'pm_score': 7, 'selected': False, 'text': '<p>Here is a way to remove non-interactively a specific <code>&lt;commit-id&gt;</code>, knowing only the <code>&lt;commit-id&gt;</code> you would like to remove:</p>\n\n<pre><code>git rebase --onto &lt;commit-id&gt;^ &lt;commit-id&gt; HEAD\n</code></pre>\n'}, {'answer_id': 4110978, 'author': 'rvernica', 'author_id': 418730, 'author_profile': 'https://Stackoverflow.com/users/418730', 'pm_score': 6, 'selected': False, 'text': '<p>As noted before <a href="http://git-scm.com/docs/git-rebase">git-rebase(1)</a> is your friend. Assuming the commits are in your <code>master</code> branch, you would do:</p>\n\n<pre><code>git rebase --onto master~3 master~2 master\n</code></pre>\n\n<p>Before:</p>\n\n<pre><code>1---2---3---4---5  master\n</code></pre>\n\n<p>After:</p>\n\n<pre><code>1---2---4\'---5\' master\n</code></pre>\n\n<p>From git-rebase(1):</p>\n\n<blockquote>\n  <p>A range of commits could also be\n  removed with rebase. If we have the\n  following situation:</p>\n\n<pre><code>E---F---G---H---I---J  topicA\n</code></pre>\n  \n  <p>then the command</p>\n\n<pre><code>git rebase --onto topicA~5 topicA~3 topicA\n</code></pre>\n  \n  <p>would result in the removal of\n  commits F and G:</p>\n\n<pre><code>E---H\'---I\'---J\'  topicA\n</code></pre>\n  \n  <p>This is useful if F and G were flawed in some\n  way, or should not be part of topicA.\n  Note that the argument to --onto and\n  the  parameter can be any\n  valid commit-ish.</p>\n</blockquote>\n'}, {'answer_id': 12567860, 'author': 'jdsumsion', 'author_id': 1667497, 'author_profile': 'https://Stackoverflow.com/users/1667497', 'pm_score': 4, 'selected': False, 'text': '<p>All the answers so far don\'t address the trailing concern:</p>\n\n<blockquote>\n  <p>Is there an efficient method when there are hundreds of revisions\n  after the one to be deleted?</p>\n</blockquote>\n\n<p>The steps follow, but for reference, let\'s assume the following history:</p>\n\n<pre><code>[master] -&gt; [hundreds-of-commits-including-merges] -&gt; [C] -&gt; [R] -&gt; [B]\n</code></pre>\n\n<p><em>C</em>:\n  commit just following the commit to be removed (clean)</p>\n\n<p><em>R</em>:\n  The commit to be removed</p>\n\n<p><em>B</em>:\n  commit just preceding the commit to be removed (base)</p>\n\n<p>Because of the "hundreds of revisions" constraint, I\'m assuming the following pre-conditions:</p>\n\n<ol>\n<li>there is some embarrassing commit that you wish never existed</li>\n<li>there are ZERO subsequent commits that actually depend on that embarassing commit (zero conflicts on revert)</li>\n<li>you don\'t care that you will be listed as the \'Committer\' of the hundreds of intervening commits (\'Author\' will be preserved)</li>\n<li>you have never shared the repository\n\n<ul>\n<li>or you actually have enough influence over all the people who have ever cloned history with that commit in it to convince them to use your new history</li>\n<li>and you <a href="http://git-scm.com/book/en/Git-Branching-Rebasing#The-Perils-of-Rebasing" rel="noreferrer">don\'t care</a> about <a href="http://www-cs-students.stanford.edu/~blynn/gitmagic/ch05.html" rel="noreferrer">rewriting history</a></li>\n</ul></li>\n</ol>\n\n<p>This is a pretty restrictive set of constraints, but there is an interesting answer that actually works in this corner case.</p>\n\n<p>Here are the steps:</p>\n\n<ol>\n<li><code>git branch base B</code></li>\n<li><code>git branch remove-me R</code></li>\n<li><code>git branch save</code></li>\n<li><code>git rebase --preserve-merges --onto base remove-me</code></li>\n</ol>\n\n<p>If there are truly no conflicts, then this should proceed with no further interruptions.  If there are conflicts, you can resolve them and <code>rebase --continue</code> or decide to just live with the embarrassment and <code>rebase --abort</code>.</p>\n\n<p>Now you should be on <code>master</code> that no longer has commit <em>R</em> in it.  The <code>save</code> branch points to where you were before, in case you want to reconcile.</p>\n\n<p>How you want to arrange everyone else\'s transfer over to your new history is up to you.  You will need to be acquainted with <code>stash</code>, <code>reset --hard</code>, and <code>cherry-pick</code>.  And you can delete the <code>base</code>, <code>remove-me</code>, and <code>save</code> branches</p>\n'}, {'answer_id': 13389977, 'author': 'kareem', 'author_id': 62251, 'author_profile': 'https://Stackoverflow.com/users/62251', 'pm_score': 7, 'selected': False, 'text': '<p>Per <a href="https://stackoverflow.com/questions/495345/git-removing-selected-commit-log-entries-for-a-repository#comment7145575_3705152">this comment</a> (and I checked that this is true), rado\'s answer is very close but leaves git in a detached head state. Instead, remove <code>HEAD</code> and use this to remove <code>&lt;commit-id&gt;</code> from the branch you\'re on:</p>\n\n<pre><code>git rebase --onto &lt;commit-id&gt;^ &lt;commit-id&gt;\n</code></pre>\n'}, {'answer_id': 26753212, 'author': 'Gautam', 'author_id': 492561, 'author_profile': 'https://Stackoverflow.com/users/492561', 'pm_score': 2, 'selected': False, 'text': '<p>So here is the scenario that I faced, and how I solved it.</p>\n\n<pre><code>[branch-a]\n\n[Hundreds of commits] -&gt; [R] -&gt; [I]\n</code></pre>\n\n<p>here <code>R</code> is the commit that I needed to be removed, and <code>I</code> is a single commit that comes after <code>R</code></p>\n\n<p>I made a revert commit and squashed them together</p>\n\n<pre><code>git revert [commit id of R]\ngit rebase -i HEAD~3\n</code></pre>\n\n<p>During the interactive rebase squash the last 2 commits.</p>\n'}, {'answer_id': 39358948, 'author': 'Sankalp', 'author_id': 1883278, 'author_profile': 'https://Stackoverflow.com/users/1883278', 'pm_score': 2, 'selected': False, 'text': '<p>I also landed in a similar situation. Use interactive rebase using the command below and while selecting, drop 3rd commit.</p>\n\n<pre><code>git rebase -i remote/branch\n</code></pre>\n'}, {'answer_id': 46213462, 'author': 'fdermishin', 'author_id': 502144, 'author_profile': 'https://Stackoverflow.com/users/502144', 'pm_score': 0, 'selected': False, 'text': '<p>Answers of rado and kareem do nothing for me (only message "Current branch  is up to date." appears). Possibly this happens because \'^\' symbol doesn\'t work in Windows console. However, according to <a href="https://stackoverflow.com/questions/37219/how-do-you-remove-a-specific-revision-in-the-git-history#comment75641303_13389977">this</a> comment, replacing \'^\' by \'~1\' solves the problem.</p>\n\n<pre><code>git rebase --onto &lt;commit-id&gt;^ &lt;commit-id&gt;\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/37219', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/3146/']