I made a change in a script and committed it. Then I made a few other changes, and pushed them to a remote repository and such.
Then I realised that first change I mentioned was stupid, and want to undo it.. Can I "unapply" that commit, without manually copy/pasting the diff?
As an example: I have two files, a.py
and b.py
:
Commit 1: I delete a function in a.py Commit 2: I change a few lines in b.py Commit 3: I change the docstring in a.py
Can I undo that function deletion, and make it appear as "commit 4" (rather than deleting commit 1)
The git revert command is a forward-moving undo operation that offers a safe method of undoing changes. Instead of deleting or orphaning commits in the commit history, a revert will create a new commit that inverses the changes specified. Git revert is a safer alternative to git reset in regards to losing work.
Yes, you can use git revert for this. See the git manual section on this for more information.
The gist is that you can say:
git revert 4f4k2a
Where 4f4k2a is the id of the commit you'd like to undo, and it will try to undo it.
Just a comment:
git revert aCommit
does revert the all commit (as in "all the files part of the commit" ):
it computes a reverse patch, applies it on HEAD and commit.
So two problems here (the first one is easily solved):
-no-commit
option: "git revert --no-commit aCommit
": this is useful when reverting more than one commits' effect to your index in a row.git-checkout
, specifically the git checkout <commit> <filename>
syntax (that is not exactly what you need in this case though)Easy Git (Elijah Newren) tried to bring a more "complete revert" to the Git Mailing list; but without much success:
People occasionally want to "revert changes".
Now, this may be:
- the changes between 32 and 29 revisions ago,
- it might be all changes since the last commit,
- it could be the changes since 3 commits ago, or
- it could be just one specific commit.
- The user may want to subset such reversions to just specific files,
(eg revert
is documented here, but I am not sure it is part of the current distribution of eg though)
but it all boils down to "reverting changes" in the end.
eg revert --since HEAD~3 # Undo all changes since HEAD~3 eg revert --in HEAD~8 # much like git revert HEAD~8, but nocommit by default eg revert --since HEAD foo.py # Undo changes to foo.py since last commit eg revert foo.py # Same as above eg revert --in trial~7 bar.c baz. # Undo changes made in trial~7 to bar.[ch]
Are these kinds of "reverting data" really so different that there should need to be different commands, or that some of these operations shouldn't be supported by the simple revert command?
Sure, most users most of the time will probably use the "eg revert FILE1 FILE2...
" form, but I didn't see the harm in supporting the extra capabilities.Also...is there anything fundamental that would keep core git from adopting such behavior?
Elijah
Note: commits by default don't make sense for the generalized
revert
command, and "git revert REVISION
" would error out with instructions (telling the user to add the --in flag).
Lets say you have, out of 50 committed, 20 files you realize that old commit X introduced changes that should not have taken place.
A little plumbing is in order.
What you need is a way to list all the specific files you need to revert
(as in "to cancel changes made in commit X while keeping all subsequent changes"),
and then, for each of them:
git-merge-file -p a.py X X^
The issue here is to recover the lost function without obliterating all subsequent changes in a.py you might want to keep.
That technique is sometime called "negative merging".
Since git merge-file <current-file> <base-file> <other-file>
means:
incorporates all changes that lead from the <base-file>
to <other-file>
into <current-file>
, you can restore the deleted function by saying you want to incorporate all changes.)
Note: the '-p
' argument which allows you to review first the changes without doing anything on the current file. When you are sure, remove that option.
Note: the git merge-file
is not that simple: you can not reference previous versions of the file just like that.
(you would have over and over the frustrating message: error: Could not stat X
)
You have to:
git cat-file blob a.py > tmp/ori # current file before any modification git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there git merge-file a.py tmp/X tmp/F # basically a RCS-style merge # note the inversed commit order: X as based, then F # that is why is is a "negative merge" diff -u a.py tmp/ori # eyeball the merge result git add a.py git commit -m "function restored" # and any other changes made from X are preserved!
If this is to be done for a large number of files within a previous commit... some scripting is in order ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With