Alex R
Alex R

Reputation: 11891

Git ignore deleted folders during a merge?

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

Answers (2)

Quentin
Quentin

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

Mark Adelsberger
Mark Adelsberger

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

Related Questions