Reputation: 3781
I would like to modify a git commit which I pushed long time ago. Is there any simple and straightforward way to do that?
I have made a lot of changes since then, and it is very confusing and risky for me to do it with git rebase
.
I can still use git rebase
but I am very new for git usage.
The commit involves the first file of my repository, and I am not allowed to create a new commit for changing a file which I pushed with my first commit.
Upvotes: 0
Views: 616
Reputation: 536027
Now that you've granted that we are allowed to make new commits to achieve the desired effect, the easy way to do this is: Do what it says at How to inject a commit between some two arbitrary commits in the past? to insert the change commit after the problem commit. Then interactive rebase to squash the inserted commit to the problem commit.
I'll demonstrate:
humlet:gittest matt$ git init
humlet:gittest matt$ echo test > dummy.txt
humlet:gittest matt$ git add .
humlet:gittest matt$ git commit -m "start"
humlet:gittest matt$ echo crucial > crucial.txt
humlet:gittest matt$ git add .
humlet:gittest matt$ git commit -m "created crucial file"
humlet:gittest matt$ echo test2 > dummy.txt
humlet:gittest matt$ git commit -am "changed dummy"
humlet:gittest matt$ echo test3 > dummy.txt
humlet:gittest matt$ git commit -am "changed dummy again"
git log
shows that the commits are
changed dummy again
changed dummy
created crucial file
start
Okay, so the goal is to change what is in crucial.txt and put that commit in place of the "created crucial file" commit. git log
shows that that commit is 785f75. Here we go:
humlet:gittest matt$ git branch temp 785f75
humlet:gittest matt$ git checkout temp
humlet:gittest matt$ echo whoa > crucial.txt
humlet:gittest matt$ git commit -am "teehee"
humlet:gittest matt$ git rebase temp master
We've now inserted a commit ("teehee") containing the revised crucial.txt, but we have one too many commits:
changed dummy again
changed dummy
teehee
created crucial file
start
So now we go back and squash "teehee" onto "created crucial file". To do so, we do an interactive rebase starting at the commit preceding both of them, which is "start"; git log
shows that that is e01e0c5:
humlet:gittest matt$ git rebase -i e01e0c5
In the interactive rebase, we pick
all the commits we are shown, except that we squash
"teehee". When we are offered a chance to revise the commit message, we change it to "created crucial file". git log
shows that we now have
changed dummy again
changed dummy
created crucial file
start
Okay, now let's check what's in the "created crucial file" commit:
humlet:gittest matt$ git diff 65c198 e01e0c
diff --git a/crucial.txt b/crucial.txt
deleted file mode 100644
index 0a6a129..0000000
--- a/crucial.txt
+++ /dev/null
@@ -1 +0,0 @@
-whoa
So, you see, it looks like "created crucial file" added crucial.txt and it consisted of "whoa". That is the desired result.
Disclaimer: Changing history that you have pushed is wrong. Don't do it.
Upvotes: 0
Reputation: 1329692
What I want to do is, changing a specific file content,
Instead of an interactive rebase, use git filter-repo
, which replaces BFG or filter-branch.
At the end, you can (if you are the only one working on that repository) do a git push --force
If you want to modify file contents, you can do so based on a list of expressions in a file, one per line.
For example, with a file namedexpressions.txt
containing:p455w0rd foo==>bar glob:*666*==> regex:\bdriver\b==>pilot literal:MM/DD/YYYY=>YYYY-MM-DD regex:([0-9]{2})/([0-9]{2})/([0-9]{4})==>\3-\1-\2
then running
git filter-repo --replace-text expressions.txt
will go through and replace:
p455w0rd
with***REMOVED***
,foo
withbar
,- any line containing
666
with a blank line,- the word
driver
withpilot
(but not if it has letters before or after; e.g. drivers will be unmodified),- the exact text
MM/DD/YYYY
withYYYY-MM-DD
and- date strings of the form
MM/DD/YYYY
with ones of the formYYYY-MM-DD
.
Upvotes: 1