Let's say I have commit 1, 2 ... 10.000.000, and I want to fixup commit 8.000.000 to 1.000, e.g sha2 is merged into sha1, keeping sha1's commit message, and keeping all other commits in order, where sha1 and sha2 are very far from each other and very far from HEAD.
This question has been asked several times, but every time it is assumed that the commits are close to each other and close to HEAD and git rebase -i HEAD~5
can be used. I just don't see how that is manageable as the number of commits scale.
I am hoping for an answer along the lines of git rebase --fixup sha2 --onto sha1
Related questions:
- Squashing commits far apart in git history despite title, question and answer assumes commits are close to each other and close to HEAD.
- how to re-order commits in Git non-interactively asks to reorder non-interactively, but top answers uses interactive rebase, and other answer suggest writing a line for each commit between sha1 and sha2
- How do I run git rebase --interactive in non-interactive manner? asks about how to export rebase list to a file for later editing.
- Squash Git commits *non-interactively* with git rebase wants to squash all commits not shared between two branches. I want to squash/fixup 1 commit into 1 other commit, keeping all other commits the same.
CodePudding user response:
I would suggest the following solution.
git checkout <COMMIT_HASH YOU WANT TO BE SQUASHED>
git reset --soft HEAD~1
git stash
This will stash changes of commit you want to squash. Then:
git checkout master
git rebase -i <BASE COMMIT HASH -1>
In the opened editor
edit <COMMIT HASH YOU WANT TO MAKE BASIC>
...
drop <COMMIT HASH YOU WANT TO SQUASH>
After rebase process stops on the commit you marked as "edit", then:
git stash pop
git add -A
git commit
git rebase --continue
CodePudding user response:
You use git rebase -i
and reorder the lines and mark the one you want to squash into the earlier one with fixup
. Yes, this opens a file with millions of lines.
Instead of doing it interactively, you can set sequence.editor
to a script that modifies the lines, for example:
git -c sequence.editor='f () {
sed -i -e '1000a fixup abcde12345' -e '8000000d' "$1"
}; f' rebase -i basecommit
Here, abcde12345
is the commit ID of the 8,000,000th commit.
If you do not want to depend on counts, but use commit IDs instead, you can do:
git -c sequence.editor='f () {
sed -i -e '/pick 54ab32/a fixup abcde12345' -e '/pick abcde123/d' "$1"
}; f' rebase -i basecommit
Note that the IDs after /pick
must be given no longer than they appear in the file (typically only 6 characters, but probably more in your case where you have millions of objects).