I have some commits in my current branch. I want to convert those all commits into one commit and delete all those commits. So I have used the following commands
- git rebase -i HEAD~9
- Edited all commits to Squash except the oldest one to Pick and saved
- Given a specific comment and saved
- git push
I ran "git push" instead of git commit followed by force push.
Now, it has created a new commit with merge of all previous commits. But it did not delete all previous commits. And I have pushed into remote.
Before rebase, following are the commit ids in my branch
commit 1 : 2c6a45b
commit 2 : <any_hash>
commit 3 : 77b9b82
commit 4 : <any_hash>
And after rebase, commit id has added to the existing one which is a merge of all above commit ids
commit 0 : b3d92c5
commit 1 : 2c6a45b
commit 2 : <any_hash>
commit 3 : 77b9b82
commit 4 : <any_hash>
So please help how can I remove previous commits and make sure that only one squashed commit is pushed into remote. Is there a way to revert or fix this from here?
CodePudding user response:
Nothing ever deletes old commits.1 Rebase makes new commits, but the old commits continue to exist. Having made the new commits, we now tell other people with other Git repositories to get these new commits (or send them to those other people using git push
) ... and then we tell them: and stop using the old commits, as these are new and improved replacement commits.
If you're using git push
to send these commits to some shared repository, you must in general use git push --force
or git push --force-with-lease
to achieve the "and stop using the old commits" part.
What you did instead—you didn't say this, but it's pretty common for people to do this by accident—was to make the new-and-improved commits, send them to another Git repository, and then merge both the old commits and the new-and-improved commits. So you now have both sets in your repository.
To fix this, you must eject the merge commit itself from the set of commits you're using. That is, you want to "remove" the merge. As we already noted, that's literally impossible, but you don't have to eradicate the merge commit from your repository; you merely have to stop using it.
The Git command that lets you stop using some particular commit is git reset
. There are some major drawbacks to using git reset
:
To stop using some commit, you must also stop using all subsequent commits on that branch.
If other people (other Git repositories) have that commit, they can give it back to your Git which will happily add it back: Git just loves to add commits, and is reluctant to stop using commits, which is why merge is easy and reset is hard.
But if you've made sure that you have no uncommitted work, you can safely run git reset --hard
now. Run git log --graph
(or see Pretty Git branch graphs) to verify that the merge commit is the tip of the branch, and to see whether the first parent of the merge is the commit you want as the new tip (this seems likely), or whether the second parent of the merge is the one you want as the new tip (less likely but possible). Then:
git reset --hard HEAD~1
will move the branch name back to the first parent of the current commit. If that's not the correct commit—if you needed the second parent—you will have instead run:
git reset --hard HEAD^2
(or in CMD.EXE
, git reset --hard HEAD^^2
). You must carefully view the commit graph first (see the linked question and its answers) to verify that the merge commit is in fact at the tip of the current branch, and that the first or second parent of the merge commit is the commit you want at the tip.
If these aren't the case, consider running:
git log --decorate --oneline --graph
and cutting-and-pasting some of the output (the part with the commits in question) into your question.
1This isn't strictly true, but there's no "remove a commit" command. Instead, we abandon old commits—stop using them—and eventually Git decides that they are not just not being used now, but can't even be found, and Git then eventually removes them on its own. Or, sometimes it doesn't. We don't really control this unless we dive deep into maintenance Git commands.
CodePudding user response:
Thanks for your comments and posts. I am able to fix this thing by using reword and drop options from git-rebase. Following below are the steps I have followed to drop other commits after squash.
- git rebase -i HEAD~2
- Opens editor with squahed commit id and previous commit ids. I think it is treating other commits as one commit. So when I requested for only 2 commits, it displayed recent squashed commit and previous all commits in the branch.
- Marked recent squashed commit as "Reword"
- Marked other previous commits as "Drop" which I want to drop from the branch, as all those commits are squashed into one commit.
- Save and Quit
- Rewrite the comment for the new commit
- Check git log. It will remove all the old commits and displays only one new commit in the branch
- git push -f (must and should).