do thing1 do thing2 REVERT "do thing1"
So the question is now : How can I remove this commit which changes nothing ?
Only rewrite that part of history which you alone possess (source) : don't amend any commit you have already pushed (source) !
If you made a commit as the wrong user (or with a wrong email value), you can fix the latest commit with :To avoid committing as root, you can add into /root/.bash_profile :
alias git='echo "Please do NOT use git as root"'
newDate='Fri Mar 13 09:24:32 2020 +0100'; GIT_COMMITTER_DATE="$newDate" git commit --amend --no-edit --date "$newDate"
The whole operation relies on an interactive git rebase, as already used to :
In the example below, let's say we want to alter the 2 latest commits.commit e6fcd18d063a6624b5fdefd27c6df646280c2788 Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Mar 13 14:57:12 2020 +0100 we're going to change this ... a very interesting commit message commit 4e9c917085e0de16db01ae1b5d793e1a9013d3f3 Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Mar 13 11:24:32 2020 +0100 ... and this another great commit message
pick 4e9c917 another great commit message pick e6fcd18 a very interesting commit message
pick
into e
(edit
). Save and close.Stopped at 4e9c917... another great commit message
You can amend the commit now, with
git commit --amend
Once you are satisfied with your changes, run
git rebase --continue
Fri Mar 13 16:51:45 2020 +0100
[detached HEAD 4d24a66] another great commit message done editing the 1st commit Date: Fri Mar 13 16:51:45 2020 +0100 Stopped at e6fcd18... a very interesting commit message starting to edit the 2nd commit You can amend the commit now, with git commit --amend Once you are satisfied with your changes, run git rebase --continue
[detached HEAD 75e964f] a very interesting commit message
Date: Fri Mar 13 16:54:45 2020 +0100
3 files changed, 39 insertions(+)
Successfully rebased and updated refs/heads/master.
commit 75e964f48eba2abee70a3530c9cd515fe2fbe155 Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Mar 13 16:54:45 2020 +0100 as expected a very interesting commit message commit 4d24a66bf88b1c8504b31b540e51c97106851e9b Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Mar 13 16:51:45 2020 +0100 as expected another great commit message
pick 17b92bc a great commit message this is the commit I want to split pick d426342 one more wonderful piece of commit message
pick
into edit
:
edit 17b92bc a great commit message pick d426342 one more wonderful piece of commit messageSave and close your editor.
Unstaged changes after reset: M roles/logrotate/defaults/main.yml M roles/logrotate/tasks/main.yml
Successfully rebased and updated refs/heads/master.
commitId^0
: the commit itselfcommitId^1
(shorthand : commitId^
) : father of commitIdcommitId^2
: mother of commitIdcommitId~0
: this is commitId itselfcommitId~1
(shorthand : commitId~
) : father of commitIdcommitId~2
: grandfather of commitIdcommitId~3
commitId^^^
commitId^1^1^1
G H I J older commits \ / \ / D E F \ | / \ \ | / | \|/ | B C \ / \ / A HEAD
commit | parent ^ |
ancestor ~ |
---|---|---|
A |
= A^0 |
|
B |
= A^ = A^1 |
= A~1 |
C |
= A^2 |
|
D |
= A^^ = A^1^1 |
= A~2 |
E |
= B^2 = A^^2 |
|
F |
= B^3 = A^^3 |
|
G |
= A^^^ = A^1^1^1 |
= A~3 |
H |
= D^2 = B^^2 = A^^^2 |
= A~2^2 |
I |
= F^ = B^3^ = A^^3^ |
|
J |
= F^2 = B^3^2 = A^^3^2 |
TO BE CONFIRMED : X^1 = X~1 X~~...~~ = X~n = the father of the father of ... of X (father / grandfather / grand-grandfather / ...) ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^ n times n times X^^...^^ = X~n ^^^^^^^ n times X^^2 must be understood (X^)^2 there's nothing you can "simplify" with : X^^...^^y, depends on the tree
On branch master Your branch is ahead of 'origin/master' by 5 commits. (use "git push" to publish your local commits) nothing to commit, working directory cleanMy log : git log --oneline
2261c3a Revert blah blah blah ... This reverts commit 190898e77999bf4041fdc6d57ec18618743302e8 a102d0a FIX (ticket-104, part 2/2) this commit 2fec5db FIX (ticket-104, part 1/2) and this one too ee00f4b Revert blah blah blah ... This reverts commit 7e16fa7173f10a662eecedbe166f42ffabacb41a 190898e ADD 'server_clone' for tests 7f2c929 FIX blah blah blah ... 8007cc6 CHANGE blah blah blah ... 3d835df FIX blah blah blah ... 5b047a8 FIX blah blah blah ... 082f84c CHANGE detailsI'd like to push only the 2 marked commits to my origin server.
A wise (best practice !) solution would have been to create a dedicated branch to work on "ticket-104", but if I knew then, I wouldn't be on the verge of learning some git push hack .
this is some code : $i
" > "$codeFile"; git add "$codeFile"; git commit -m "This is commit #$i ($codeFile)"; done; git log --onelineInitialized empty Git repository in /dev/shm/playingWithGit.0teQbNFk/myRepo.git/ Cloning into 'myRepo'... warning: You appear to have cloned an empty repository. [master (root-commit) 0e0fe97] This is commit #1 (file1) 1 file changed, 1 insertion(+) create mode 100644 file1 [master 8488863] This is commit #2 (file2) 1 file changed, 1 insertion(+) create mode 100644 file2 [master af6011d] This is commit #3 (file3) 1 file changed, 1 insertion(+) create mode 100644 file3 [master 1503eac] This is commit #4 (file4) 1 file changed, 1 insertion(+) create mode 100644 file4 [master 828be7d] This is commit #5 (file5) 1 file changed, 1 insertion(+) create mode 100644 file5 828be7d (HEAD -> master) This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
On branch master Your branch is up-to-date with 'origin/master'.
this is some code : $i
" > "$codeFile"; git add "$codeFile"; git commit -m "This is commit #$i ($codeFile)"; done; git log --oneline[master 725708b] This is commit #6 (file6) 1 file changed, 1 insertion(+) create mode 100644 file6 [master 0021c6d] This is commit #7 (file7) 1 file changed, 1 insertion(+) create mode 100644 file7 [master 58ce856] This is commit #8 (file8) 1 file changed, 1 insertion(+) create mode 100644 file8 58ce856 (HEAD -> master) This is commit #8 (file8) 0021c6d This is commit #7 (file7) 725708b This is commit #6 (file6) 828be7d (origin/master) This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
58ce856 (HEAD -> master) This is commit #8 (file8) 0021c6d (origin/master) This is commit #7 (file7) 725708b This is commit #6 (file6) 828be7d This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
I've actually pushed the commits This is commit #6 (file6) and This is commit #7 (file7)
this is some code : $i
" > "$codeFile"; git add "$codeFile"; git commit -m "This is commit #$i ($codeFile)"; done; git log --oneline07b6bb8 (HEAD -> master) This is commit #13 (file13) 65100fc This is commit #12 (file12) 48e1df2 This is commit #11 (file11) a51d31f This is commit #10 (file10) 4abcf38 This is commit #9 (file9) 58ce856 This is commit #8 (file8) 0021c6d (origin/master) This is commit #7 (file7) 725708b This is commit #6 (file6) 828be7d This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
7
again, like the "head" of the remote branch, but this is purely coincidental.pick 0021c6d This is commit #7 (file7) pick 48e1df2 This is commit #11 (file11) pick 4abcf38 This is commit #9 (file9) pick 58ce856 This is commit #8 (file8) pick a51d31f This is commit #10 (file10) pick 65100fc This is commit #12 (file12) pick 07b6bb8 This is commit #13 (file13)
02c9072 (HEAD -> master) This is commit #13 (file13) 8082015 This is commit #12 (file12) cf3cda0 This is commit #10 (file10) e794a70 This is commit #8 (file8) 926ad50 This is commit #9 (file9) 117bb7f This is commit #11 (file11) 0021c6d (origin/master) This is commit #7 (file7) 725708b This is commit #6 (file6)
On branch master Your branch is ahead of 'origin/master' by 6 commits. (use "git push" to publish your local commits)
Counting objects: 6, done. Delta compression using up to 2 threads. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 579 bytes | 579.00 KiB/s, done. Total 6 (delta 2), reused 0 (delta 0) To file:///run/shm/playingWithGit.0teQbNFk/myRepo.git/ 0021c6d..926ad50 926ad50 -> master
On branch master Your branch is ahead of 'origin/master' by 4 commits. (use "git push" to publish your local commits)And :
02c9072 (HEAD -> master) This is commit #13 (file13) 8082015 This is commit #12 (file12) cf3cda0 This is commit #10 (file10) e794a70 This is commit #8 (file8) 926ad50 (origin/master) This is commit #9 (file9) 117bb7f This is commit #11 (file11) 0021c6d This is commit #7 (file7) 725708b This is commit #6 (file6) 828be7d This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
926ad50 (HEAD -> master) This is commit #9 (file9) 117bb7f This is commit #11 (file11) 0021c6d This is commit #7 (file7) 725708b This is commit #6 (file6) 828be7d This is commit #5 (file5) 1503eac This is commit #4 (file4) af6011d This is commit #3 (file3) 8488863 This is commit #2 (file2) 0e0fe97 This is commit #1 (file1)
NEVER EVER rebase commits which you have already pushed to a remote repository !
testFile='./myFile'; testDir='./myDir' mkdir "$testDir"; cd "$testDir" git init; touch "$testFile"; git add "$testFile"; git co "$testFile" -m "Initial version (empty)"; git log for i in {1..4}; do echo "This is edit number $i" >> "$testFile"; git co "$testFile" -m "Commit #$i"; done; git log
pick 897931d Commit #3 pick 25d3585 Commit #4Edit to squash the 4th commit into the 3rd (forget about commit messages for the moment) :
pick 897931d Commit #3 s 25d3585 Commit #4Save and exit. Then you'll be prompted for the final commit message :
# This is a combination of 2 commits. # The first commit message is: Commit #3 # This is the 2nd commit message: Commit #4Enter your own commit message :
Squashed #4 into #3Save and exit. Check the result with git log :
Squashed #4 into #3 Commit #2 Commit #1 Initial version (empty)
Make sure you've run the cleaning then preliminary steps before going further.
git rebase -i HEAD~3 outputs :pick 04f56e2 Commit #2 pick 0887de3 Commit #3 pick 5410e2c Commit #4Edit to fixup the commits 2, 3 and 4 and use the message of the 2nd commit (this method won't prompt for a commit message):
pick 04f56e2 Commit #2 f 0887de3 Commit #3 f 5410e2c Commit #4Save and exit. Check with git log :
Commit #2 Commit #1 Initial version (empty)See changes made with this "new commit number 2" (that is also the latest so far) : git show HEAD~1..HEAD $testFile :
Commit #2
diff --git a/myFile b/myFile
index 32671c8..4e96082 100644
--- a/myFile
+++ b/myFile
@@ -1 +1,4 @@
This is edit number 1
+This is edit number 2
+This is edit number 3
+This is edit number 4
Make sure you've run the cleaning then preliminary steps before going further.
git log shows :commit 402957e89a359ce2bd4c9c24cd658dbe25a4f155 Commit #4 commit 331174ab513dda7861100997ae6e4dbf66d18eae Commit #3 commit de0db9b72fad2e52b23cbfdd51f8714561d9e0e6 Commit #2 commit 8c93f6861a17388d691cfb5a985bbb9161c4a8f1 Commit #1 commit 8ee9ad23f95c146d48c7c7a7f58d03a3140e5455 Initial version (empty)We're at Commit #4 (HEAD) and we want to make changes right after Commit #1, no matter where these changes stop. In other words, we want to start working from Commit #1 (excluded), which can be refereed to as HEAD~3 (details)
pick de0db9b Commit #2 pick 331174a Commit #3 pick 402957e Commit #4 # These lines can be re-ordered; they are executed from top to bottom.Edit (this is where the magic takes place ) Forget about commit message for the moment :
pick de0db9b Commit #2 s 331174a Commit #3 pick 402957e Commit #4Save and exit. You'll be prompted for a new commit message :
# This is a combination of 2 commits. # The first commit message is: Commit #2 # This is the 2nd commit message: Commit #3Change this into :
Squashed #3 into #2And check the result : git log :
commit ff477d71a329265bf2033d0d0ccd5a1c7e60c37c Commit #4 commit 394bc1c28075e6457a795bd69d58deda20f00a20 Squashed #3 into #2 commit 8c93f6861a17388d691cfb5a985bbb9161c4a8f1 Commit #1 commit 8ee9ad23f95c146d48c7c7a7f58d03a3140e5455 Initial version (empty)See changes made with this "new commit" : git show HEAD~2..HEAD~1 $testFile :
commit 394bc1c28075e6457a795bd69d58deda20f00a20
Squashed #3 into #2
diff --git a/myFile b/myFile
index 32671c8..987d059 100644
--- a/myFile
+++ b/myFile
@@ -1 +1,3 @@
This is edit number 1
+This is edit number 2
+This is edit number 3
rm -rf .git; cd ..; [ -d "$testDir" ] && rm -r "$testDir"; unset testFile testDir
To highlight the changes made between commits, use --word-diff (works with diff / show / log) :
Only rewrite that part of history which you alone possess (source) : don't alter a commit you have already pushed (source) !
commit 7ef72d73aa0ee4c67007e66a3351ed1ee2df6998 Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Apr 24 15:31:11 2015 +0200 commit message #3 commit 2b9bbbf3f7463e0c0526a69edec10a708dacada3 Author: root <root@localhost> OOOPS ! Date: Fri Apr 24 15:21:21 2015 +0200 commit message #2 commit f93811c3dcaabed86df54916ea84fbbfcf521435 Author: Thomas ANDERSON <thomas.anderson@metacortex.com> Date: Fri Apr 24 11:44:25 2015 +0200 commit message #1
* master
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.
...
HEAD is now at 2b9bbbf... commit message #2
First, rewinding head to replay your work on top of it...
Applying: commit message #3
git log -S my file
will show the history of my file starting at the rename commit, back to the beginning of times.tempDir=$(mktemp -d --tmpdir XXXXXXXX); commitMessage='This is commit '; cd "$tempDir"; git init; echo 'hello world' > myFile; git add myFile; git co -m 'Initial version'; for i in {1..2}; do echo "This line will be committed by commit #$i" >> myFile; git add myFile; git co -m "$commitMessage#$i"; done; git log --oneline; idOfLatestCommit=$(git log --oneline | awk "/$commitMessage#$i/ {print \$1}"); echo -e "\nID of latest commit : '$idOfLatestCommit'\nREVERTING...\n"; git revert --no-edit "$idOfLatestCommit"; git log --oneline; echo; git s; echo; cat myFile; cd -; [ -d "$tempDir" ] && rm -rf "$tempDir"
Outputs :aa94778 This is commit #2 5915e56 This is commit #1 9baee48 Initial version ID of latest commit : 'aa94778' REVERTING... [master 5ba510a] Revert "This is commit #2" 1 file changed, 1 deletion(-) 5ba510a Revert "This is commit #2" aa94778 This is commit #2 5915e56 This is commit #1 9baee48 Initial version On branch master nothing to commit (use -u to show untracked files) nothing unstaged hello world This line will be committed by commit #1 changes are gone : working copy altered
tempDir=$(mktemp -d --tmpdir XXXXXXXX); cd "$tempDir"; git init; echo 'hello world' > myFile; git add myFile; git co -m 'Initial version'; for i in {1..2}; do echo "This line will be committed by commit #$i" >> myFile; git add myFile; git co -m "This is commit #$i"; done; git log --oneline; echo -e '\nRESETTING...\n'; git reset HEAD^; git log --oneline; git s; cat myFile; cd -; [ -d "$tempDir" ] && rm -rf "$tempDir"
Outputs :4caee4f This is commit #2 b78d9b4 This is commit #1 e4dd720 Initial version RESETTING... Unstaged changes after reset: M myFile b78d9b4 This is commit #1 e4dd720 Initial version On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: myFile no changes added to commit (use "git add" and/or "git commit -a") hello world This line will be committed by commit #1 This line will be committed by commit #2 changes are still there : working copy unaltered
tempDir=$(mktemp -d --tmpdir XXXXXXXX); cd "$tempDir"; git init; echo 'hello world' > myFile; git add myFile; git co -m 'Initial version'; for i in {1..5}; do echo "This line will be committed by commit #$i" >> myFile; git add myFile; git co -m "This is commit #$i"; done; git log --oneline
378563c (HEAD -> master) This is commit #5 0d40646 This is commit #4 45a0af4 This is commit #3 3cfb370 This is commit #2 afa7d15 This is commit #1 f280ab7 Initial versionWe have created a repository with 5 commits, and we'll remove the commit #3.
Unstaged changes after reset: M myFile
3cfb370 (HEAD -> master) This is commit #2 afa7d15 This is commit #1 f280ab7 Initial versionJumping 3 commits back took us to the commit #2. The commits #3, #4 and #5 don't exist anymore.
hello world
This line will be committed by commit #1
This line will be committed by commit #2
+This line will be committed by commit #3
+This line will be committed by commit #4
+This line will be committed by commit #5
The changes made by the commits #3, #4 and #5 are still there. The current situation is like :
workshere because we're in a trivial situation. It implies re-doing things manually, which is long and error-prone.
pick 45a0af4 This is commit #3 pick 0d40646 This is commit #4 pick 378563c This is commit #5and a complete help message on what's going on.
Auto-merging myFile CONFLICT (content): Merge conflict in myFile error: could not apply 0d40646... This is commit #4 the problem Resolve all conflicts manually, mark them as resolved with the solution git add/rm conflicted_files, then run git rebase --continue. You can instead skip this commit: run "git rebase --skip". To abort and get back to the state before "git rebase", run "git rebase --abort". Could not apply 0d40646... This is commit #4
hello world This line will be committed by commit #1 This line will be committed by commit #2 ++<<<<<<< HEAD delete this line to resolve the conflict ++======= delete this line to resolve the conflict + This line will be committed by commit #3 delete this line to resolve the conflict + This line will be committed by commit #4 ++>>>>>>> 0d40646... This is commit #4 delete this line to resolve the conflict
[detached HEAD 7550077] This is commit #4 1 file changed, 1 insertion(+) Successfully rebased and updated refs/heads/master.
d9a6cc4 (HEAD -> master) This is commit #5 7550077 This is commit #4 3cfb370 This is commit #2 afa7d15 This is commit #1 f280ab7 Initial versionNo commit #3 anymore. The IDs of commits #4 and #5 have changed since that part of the history has been re-written.