Here's an alternate approach that has some down-sides, so consider carefully if it meets your needs:
From the restriction of 'specific files', I believe that you care only about the state of files, not necessarily what the logical change is (i.e. this file change because of bug-fix #149). That is, I only want these specific files to match the contents in the dev
branch.
Remember that a git commit isn't a set of changes, it's a point-in-time snapshot of the files when that commit was made. All the diff output between main
, dev
, 93ab34de
and 7752fbe
isn't saved in the commit object, all those diffs are computed dynamically when you run the git diff
command. Replaying those commits (cherry-picking) isn't about getting the file to the same point, it's about bringing that history -- those points in time combined with the rationale of why these changes were made -- into the main branch.
After the cherry-pick, the narrative of how main
got to its current state includes commit messages that discuss bug-fix #149, feature Y, and code-refactor-for-clarity as well as the state of the files after each of these logical commits was made. If you need to revert main
, the commit messages help you quickly understand the context of why these files were changed. For example, commit 7752fbe
can be targeted because feature Y has a performance regression.
But in this question, the request seems to worry more about the state of specific files, rather than bringing specific bits of history forward. The history is about a set of files. The request seems to be "I need this end state", rather than the change (after all, the change may involve more files than the ones we've named).
A solution, then:
- from
main
, create and enter a new branch (for hygiene); call it surgery
git checkout dev -- [file1, file2, file3]
- test to make sure your code is now as desired
- create a new commit; this captures the state of
main
+ those files you've checked out from dev
.
- go back to
main
and merge your surgery
commit.
Conceptually, surgery
is similar to a squash-merge of all those cherry-picked commits.
The downside of this, and any squash merge, is that you lose the metadata around the code development. Git is no longer tracking the individual commits around the intermediate changes. A kludge here would be to include git log main..dev
as part of the surgery
commit message.
A separate downside is confirming that the changes are complete. When commit 'feature Y' was made, it was a logical set of changes that git-author made, and could describe the rationale for those changes. Presumably he/she/they had tested the quality of the change. That is, they verified that everything worked at each point-in-time of each commit. If a change of file1 implied an update of file2, then their commit includes that. In our git checkout
approach, we could miss such repercussions. As such, be very careful in validating functionality of the entire code-base when making your surgery
commit.