Git revert after code moved to another file
TL;DR
git show -R <commit> > revert.patch
to generate a reverse patchpatch <file> revert.patch
to apply the patch to the correct file (the one where the code was moved to)
Reverting a commit
git revert
undoes changes done in some earlier commit. It assumes the files
are still in the same place, and the code has not been moved around.
$ git commit -m "feat: risky feature"
[main e86576e] feat: risky feature
1 file changed, 1 insertion(+), 1 deletion(-)
$ git revert HEAD --no-edit
[main b0eb58b] Revert "feat: risky feature"
Date: Fri May 9 21:26:20 2025 +0200
1 file changed, 1 insertion(+), 1 deletion(-)
$ git log -n 1
commit b0eb58b496ac695bc33a1f03d4363da56692ed28
Author: Grzegorz Rozdzialik <voreny.gelio@gmail.com>
Date: Fri May 9 21:26:20 2025 +0200
Revert "feat: risky feature"
This reverts commit e86576e2db771f7f4898be48590f98b841babee9.
What if you want to revert an earlier commit, and the code has been moved to another file in the meantime?
Reverting after a file was renamed
If the entire file was moved, then git will most likely be smart enough to
notice that was a file rename/move (notice the rename
in the git commit
output below), and it will git revert
will work just fine.
$ git commit -m "chore: move journal"
[main 6dbc8f9] chore: move journal
1 file changed, 0 insertions(+), 0 deletions(-)
rename journal.txt => journal-2.tx (100%)
$ git revert HEAD~ --no-edit
[main e30fd93] Revert "feat: risky feature"
1 file changed, 1 insertion(+), 1 deletion(-)
Dealing with moved code
Problems happen when only part of the code was moved, e.g. when a file was
sliced and some code was extracted. Then, git will not know what to do, and
git revert
will refuse to work.
$ git revert HEAD~
Auto-merging Header.tsx
CONFLICT (content): Merge conflict in Header.tsx
error: could not revert 8409ca0... refactor: change styles
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git revert --continue".
hint: You can instead skip this commit with "git revert --skip".
hint: To abort and get back to the state before "git revert",
hint: run "git revert --abort".
$ git diff
diff --cc Header.tsx
index e6629be,52520cd..0000000
--- a/Header.tsx
+++ b/Header.tsx
@@@ -98,6 -97,16 +98,30 @@@ const GitHubIcon = () =>
);
};
++<<<<<<< HEAD
++||||||| 8409ca0 (refactor: change styles)
++const StyledIconLink = styled("a")(({ theme }) => ({
++ textDecoration: "none",
++ transition: "filter ease-in-out 200ms",
++ "--shadowRadius": "5px",
++ filter: `drop-shadow(0 0 var(--shadowRadius) ${theme.color.shadow()})`,
++ ":hover": {
++ "--shadowRadius": "10px",
++ },
++}));
++
++=======
+ const StyledIconLink = styled("a")(({ theme }) => ({
+ textDecoration: "none",
+ transition: "filter ease-in-out 200ms",
+ "--shadowRadius": "1px",
+ filter: `drop-shadow(0 0 var(--shadowRadius) ${theme.color.shadow()})`,
+ ":hover": {
+ "--shadowRadius": "2px",
+ },
+ }));
+
++>>>>>>> parent of 8409ca0 (refactor: change styles)
const RSSIcon = () => {
const theme = useTheme();
const size = theme.spacing(3);
The output is pretty unhelpful. It tries to revert the change, but the code is no longer there.
I know that I moved the code to StyledIconLink.tsx
. I would love to tell
git revert
to try to apply that revert patch not to Header.tsx
, but to
StyledIconLink.tsx
. The way to do that is to:
- Generate a reverse patch (e.g. using
git show -R
) - Apply that patch manually to the correct file using
patch
$ git show -R HEAD~ > revert.patch
$ patch StyledIconLink.tsx revert.patch
patching file StyledIconLink.tsx
No such line 37 in input file, ignoring
1 out of 2 hunks failed--saving rejects to StyledIconLink.tsx.rej
The patch
command:
-
reverted as much of
StyledIconLink.tsx
as it could$ git diff diff --git a/StyledIconLink.tsx b/StyledIconLink.tsx index d95a425..f8e0e1d 100644 --- a/StyledIconLink.tsx +++ b/StyledIconLink.tsx @@ -1,9 +1,9 @@ export const StyledIconLink = styled("a")(({ theme }) => ({ textDecoration: "none", transition: "filter ease-in-out 200ms", - "--shadowRadius": "5px", + "--shadowRadius": "1px", filter: `drop-shadow(0 0 var(--shadowRadius) ${theme.color.shadow()})`, ":hover": { - "--shadowRadius": "10px", + "--shadowRadius": "2px", }, }));
-
said that it could not revert everything, and reported that in
StyledIconLink.tsx.rej
- makes sense, because that commit changed code outside ofStyledIconLink.tsx
as well. This shows which other code I need to revert manually.$ cat StyledIconLink.tsx.rej @@ -38,7 +38,7 @@ href={githubProfileLink} target="_blank" rel="noopener" - aria-label="GitHub profile" + aria-label="My GitHub profile" > <GitHubIcon /> </StyledIconLink>
-
created a
StyledIconLink.tsx.orig
file with the original contents of the file (pre-patch). This is most likely pointless, because you are already using git, so you can easily go back to the original content ofStyledIconLink.tsx
.
Switcheroo: generate a normal patch, and patch in reverse
Instead of tucking the -R
flag to the git show
command, you can also add it
to the patch
command:
git show HEAD~ > normal.patch
patch -R StyledIconLink.tsx normal.patch
This has the same effect. Choose whichever you prefer.