I honestly wouldn't do this unless you have a huge list of commits that need to split up and they are very independent features, i.e. not altering the same line where there would be conflicts to resolve.
As others have suggested, create a new branch for each feature and use git rebase --interactive
to include the desired commits.
To ensure none go astray, create the contents of the git-rebase-todo
files by
- editing a list of all the desired commits and classifying them by feature
- separating the list of commits into separate files
You can create the list of commits by using a command like
git log --oneline --reverse 44e19^... > log.txt
to display commit 44e19 onwards. This will give you a file like this
44e1936 dSRGratuities (SummaryRecord)
67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
69d70e2 Receipt Report: Payment
....
which when edited (to add classification: feature a,b,c etc) might look like my sorted.txt
c 44e1936 dSRGratuities (SummaryRecord)
a 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
b 69d70e2 Receipt Report: Payment
c abea7db Receipt Report: Cashback
a cf96185 Receipt Report: Gratuity
c 70e987a Receipt Report: use amount tendered for printing
a 7722ac8 Receipt Report: use amount tendered for calculations
c 47f1754 Receipt Report: store amount tendered
b b69a73f Receipt Report: Use enum Paym_FieldCount
a 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
c ad67e79 Use SharpReport enum
b 3c510c6 enum SharpReport
a e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
b 4e0c3e4 m_Gratuities m_szGratuities (SalesSummaryRecord)
b bd054f7 _gx_fn_Cashback
Then script in your favorite scripting language to turn the sorted list into a collection of git-rebase-todo
files. Your script might resemble the one I just wrote.
foreachline text sorted.txt {
set fields [split $text { }]
set branch [lindex $fields 0]
set commit [lindex $fields 1]
set comment [string range $text 10 end]
set command "echo pick $commit $comment"
exec cmd /S /C $command >> $branch.txt
}
The script reads the commit sorting file line by line and splits by a space character { } to get the two fields branch
and commit
, and takes a substring (characters 10 onwards) for a description of the commit. The description isn't required but it's useful for us humans to check for mistakes.
It then puts a line into the appropriate git-rebase-todo
file, creating one file per feature. I hacked this by executing a very ugly Windows echo string >> file
command.
This creates a number of files, e.g. my file a.txt
pick 67fedda Receipt Report HEADER: 20! multiply by Paym_FieldCount
pick cf96185 Receipt Report: Gratuity
pick 7722ac8 Receipt Report: use amount tendered for calculations
pick 9a0b471 Receipt Report HEADER: enum PaymentEntries (with Paym_FieldCount)
pick e470e07 m_Gratuities m_dSSGratuities (SalesSummary)
The whole thing is ugly. I don't recommend it unless you have to do it and are good at writing scripts.
I wrote the text above some time ago, and I have had a little rethink about things. Above I implied that this is a lot of work and not worth doing, but I have since seen situations where it looks like someone has done the above and it has been very worthwhile.
I remember releases of Visual Studio for MFC/C++ where each new release would have compiler changes, IDE changes, MFC improvements, and run on a later version of Windows. This meant that if you wanted to get your compiler away from VS6 and Windows XP you might have to make language changes to satisfy the compiler, and function call changes to satisfy MFC, etc.
Now suppose that Microsoft had taken weekly backups as they developed Visual Studio, and someone methodically took the old backups and committed the code changes into a version control system like Git. Then they started classifying the changes ...
Microsoft could create branches for each of these, and start to have the latest and greatest IDE (c
included), running on the newest Windows and still capable of compiling old legacy programs using the language (no a
) and libraries (no b
) they were written for.
Developers previously locked into legacy software could then make improvements in a logical and incremental fashion, e.g. language changes and library changes independently of each other, and do it on the latest and greatest Visual Studio without having to pass through all the intermediate versions.
Example
<LanguageStandard>stdcpp14</LanguageStandard>
Now I am not saying this is what has happened, but it seems to me that the recent versions of Visual Studio are far better at allowing legacy programs to be updated, rather than thrown away and (never?) rewritten, and it appears to me to be due to version controlling and organizing old software changes into logical branches: compiler versions, DLL/library versions.
So, I can see occasions where splitting a huge number of old commits into distinct branches may be worthwhile.
On Visual Studio 2019 I can add the line
<PlatformToolset>v141_xp</PlatformToolset>
to a configuration file and manage to compile and run an old windows program which failed to compile and link with VS 2015, and VS 2017. It looks very much like someone at Microsoft has rebased performance and security improvements onto some old software while leaving out the breaking changes
that often come with modernization.
rerere
to help if you run into the same conflicts again and again. – Duchamp