Reputation: 11891
A developer has been working on some feature branch f1
that branched off of master
.
Due to poor modularization of the repo (the system is modular, but lives in a monolithic repo) and other reasons, the developer decided to delete "a bunch of irrelevant stuff" (other modules unrelated to his feature) in the f1
branch. The feature unit-tests successfully, but the branch now contains all these deletions of entire other modules of the system.
What is the easiest, most painless way to merge f1
back into master
while ignoring folder deletions? Assume some of the files modified in f1
were also modified in the evolution of master
.
Additional Requirement
Work on the f1
branch may need to continue for a little while after the merge. I'm not quite sure how the answers proposed so far would impact that.
Upvotes: 1
Views: 1366
Reputation: 63144
I hope my git-fu is up to par.
Supposing that MERGE_SOURCE
is the branch you want to merge from, here F1
, and PRESERVED_PATHS
is the list of paths that need to be revived:
# Find out the commit from which F1 forked
MERGE_SPLIT_POINT=`git merge-base HEAD ${MERGE_SOURCE}`
# Rewrite the branch's history to unstage all changes
# (including removals) of the preserved paths
git filter-branch \
--index-filter 'git reset ${MERGE_SPLIT_POINT} -- ${PRESERVED_PATHS}' \
-- ${MERGE_SPLIT_POINT}..${MERGE_SOURCE}
# Regular merge with the resulting new branch
git merge ${MERGE_SOURCE}
Upvotes: 1
Reputation: 45739
Assuming the quality of your source history is a priority, I would recommend rewriting the history of F1
to exclude the deletes. Any "painless fix" is going to leave weird deletes and adds that will complicate future analysis of the project evolution.
(As an aside, the practice of deleting "parts of the project I'm not working on" is objectively incorrect. See "sparse checkout" for a potential solution that is not objectively incorrect.)
The more developers that have a copy of the F1
branch, and the more changes (if any) anyone has that are based on the F1
branch, the more tedious a history rewrite would be. However, if this is a feature branch that was only worked on by the one developer, and no merge of the feature has been pushed to origin, then it may be rather straightforward.
If F1
itself is linear, a rebase will do. For example
x -- x -- x -- x <--(master)
\
A -- B -- C <--(F1)
Because master..F1
(the set of commits reachable from F1
but not reachable from master
; A
, B
, and C
in this example) does not include any merges, and no other branches are based on any commit in master..F1
, this is a simple case for rebase.
git rebase -i master f1
You'll see a "TODO" list containing an entry for each commit on F1
. Change the first commit's command from pick
to edit
. Exit the editor and the rebase begins.
The rebase pauses and gives you a prompt after tentatively accepting A
"as is". Now you need to put back the files that were deleted. You can use something like git show --name-status
to identify the deleted files, and git checkout HEAD^ -- path/to/deleted/file/or/directory
to restore something that was deleted.
Once you've restored all of the files, git commit --amend
. Then continue the rebase.
There are other procedures as well that will work; this is one of the simplest cases.
After the rebase, if F1
has ever been pushed before, then you probably need to force-push it. git push -f
At this point anyone who has a copy of F1
in their local repo needs to recover (see "recover from upstream rebase" in the git rebase
documentation). If anyone has worked based on F1
they'll have to rebase it to the new F1
.
You should be able to complete the merge against the new F1
without delete issues.
Upvotes: 1