0

I often push a branch to master, after realizing I made small mistakes. Could be a wrong filename, or missing a comma somewhere. Regardless of the scenario, I am looking for a way to completely modify a pushed commit files WITHOUT making a new commit on top.

I have tried using got commit --amend and git rebase, but they always add another commit ontop.

And yes I am aware of the dangers of doing this, but I am working on this project alone, so it is very much needed.

Rich
  • 109
  • 1
  • 9
  • 3
    `--amend` should replace the previous commit with a new one. It should not add a new commit on top. Please verify that you did it correctly, and if in doubt, post the commands so that someone can help you spot the mistake. – Lasse V. Karlsen Mar 10 '20 at 12:07
  • Skip the rebase, just force-push the amended commit. – jthill Mar 10 '20 at 12:14
  • Does this answer your question? [How to modify a specified commit?](https://stackoverflow.com/questions/1186535/how-to-modify-a-specified-commit) – Enrico Campidoglio Mar 10 '20 at 13:29

2 Answers2

0

If you wish to modify just the last commit, or alternatively replace all the last x commits with one fixed commit, you can find this solution a bit easier:

Reset to the previous commit, modify your changes and than carefully push with force flag.
Be aware that after pushing with force flag you will not be able to access your old "mistaken" master commit, or any changes made after the commit you reset to; so make sure you didn't screw anything up before pushing.

git reset HEAD~1 //Previous commit
//Modify changes
git add -A
git commit -m "..."
git push --force  

In order to replace the last two commits, the first line in the above snippet should be replaced with git reset HEAD~2, number 3 for the last three and x for the last x.

Ofek Hod
  • 3,544
  • 2
  • 15
  • 26
0

It's technically impossible to change any commit. But that's not really a problem, because it is technically simple and easy to replace a commit, or even a whole chain of commits, with new and improved replacements. The issue here is not replacing the commits, but rather, because Git is distributed, updating every copy of the repository, including all the clones everyone else made.

The question you must answer first, before you do anything else, is: Who else has this commit? To have a commit that you made, you have to have given it to someone else. Once one other person has it, they might tell their friends, who tell their friends, and in a few milliseconds, that one commit you made is spread through ten thousand clones.

Normally, you'd give a new commit to, say, GitHub, using git push. If you already did a git push, then at least the Git repo on GitHub has your commit. Anyone else who can access your repository there, might also have copied it from there. Are they all going to switch from your previous commit to your new and improved commit? If so, feel free to replace your bad commit with your new and improved one. Or, if nobody else should have it, or you don't care if they do, again, you can proceed.

There are therefore two steps: replace the commit locally, then convince other Gits to do the same

To replace a commit locally, you can:

  • use git commit --amend (easiest for the last one)
  • use git reset, as outlined in another answer just posted
  • use git rebase -i, as suggested in comments and a linked almost-duplicate
  • do anything else you like: this repository is your clone, you can do whatever you want! But the three methods above are probably the easiest.

Once you have done the local replacement, you must convince the other Git—the one over on GitHub or wherever it is you git push to—that they should throw out your old commits in favor of your new and improved replacement commits. To to that, you generally need to use git push --force or git push --force-with-lease.

Both operations tell the other Git: Yes, I know this action will throw out some old commit(s). Do it anyway! They turn what is otherwise a polite request, please, if it's OK, set your branch name to a forceful command: Set your branch name! As long as you have permission to make such demands, the other Git will obey your Git's force-push.

The difference between a plain git push --force and a git push --force-with-lease is that with --force-with-lease, your Git sends a more complicated command, of the form: I think your branch _____ points to commit _____. If I'm right, set it to _____ instead. Either way, let me know if I was right. (Your Git fills in these blanks with the branch name you want their Git to change—i.e., the name you use in your git push—and the two commit hash IDs.)

That means the --force-with-lease option lets you update a shared GitHub repo while checking that what you're doing is just replacing your mistake. If your GitHub repository isn't shared, there's no need for the fancier option.

Using git commit --amend is easy

After you make a commit, if you realize there is something minor wrong with it, you just:

  • fix any files needed and git add them if needed
  • then run git commit --amend

The --amend option tells your Git: shove the last commit out of the way, making this new commit replace it rather than adding on to it. You get the opportunity to edit the commit message again—you can use --no-edit to suppress this, if the commit message is good—and when you're done, the old commit is nowhere to be seen. It's still there in your repository, you just can't see it any more. The old commit will stick around for a while—at least 30 days by default—and you can get it back if needed, but mostly, it's been replaced by the new one; the new one is what you will see.

Having shoved the old commit out of the way and replaced it with a new and improved one, you may now need to use git push --force or git push --force-with-lease to convince another Git repository to also shove the old commit out of the way in favor of a new one. Remember that this other Git repository might, if it's shared, have several contributors' new commits built up atop your commit by now: to shove yours aside, you'll have to shove all of theirs aside as well!

torek
  • 448,244
  • 59
  • 642
  • 775