Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to only merge changes added after a certain revision (both ways)?

Can git merge mostly ignore some file deletions and file renames between two branches, while merging only subsequent changes to the files that were renamed (and ignoring changes to the files that were deleted in one branch), back and forth between the two branches?

Thus, I would like to be able to merge changes both ways between two branches. The development branch is initially a copy of the master branch, but with numerous deletions and file renames.

This last point is what breaks the method I tried:

  • On master, I did a merge -s ours development (no file changed).
  • Similarly on development, I did merge -s ours master (no file changed).

I was hoping that this would somehow define some starting point, so that any subsequent git merge from any of the branches would only apply the changes made since the two merges above. Instead, the merge results in the branches becoming identical (as far as I can see), whereas I need to keep the development branch lean and clean (fewer files, better file locations), and the master branch complete (all the files, in locations appropriate for deployment)—while being able to import all changes (after the initial deletions and renames) both ways. Can this be done with git?

like image 620
Eric O Lebigot Avatar asked Aug 14 '15 08:08

Eric O Lebigot


People also ask

What is the best merge strategy?

The most commonly used strategies are Fast Forward Merge and Recursive Merge. In this most commonly used merge strategy, history is just one straight line. When you create a branch, make some commits in that branch, the time you're ready to merge, there is no new merge on the master.

Which strategy is used by git for merging two branches?

Recursive. This operates on two heads. Recursive is the default merge strategy when pulling or merging one branch. Additionally this can detect and handle merges involving renames, but currently cannot make use of detected copies.


1 Answers

After carefully reviewing the documentation at https://www.kernel.org/pub/software/scm/git/docs/git-merge.html:

The main idea of merge is, in a sense, to actually try to make the current branch identical to another branch or a specific commit in another branch, by incorporating changes that happened since they diverged from one of them into the other, which is exactly the behavior you are getting. Keyword being "diverged". You can specify which commit to merge 'up to' but not a commit since when you want to merge, merge always goes back in history up to the moment the two threads where identical or to the beginning of them, then replays the changes that happened in the merge-source again on the merge-target. This part of the behavior (where it first tries to find a common ancestor for both points and replay the changes from that point) is not changeable by any option in the merge command, no merge-strategy can change that. ours instructs it to ignore changes from other branches and always end up having the current branch's tree as the end result. recursive -Xours makes it merge and favor the current branch's version in conflicts, but both first go back to the common point or to the beginning of history for the merge source.

What I understood is this: you have a project with say a large tree and lots of files. While developing features you want to concentrate on those files you will be modifying so you delete some files, rearrange them to be easier to handle, work on them, then want to integrate the changes into the master branch. This is simply not what merge is intended to do obviously. There's no option for the command that simply tells it to start the merge from a specific point forwards

However, you might, with a small change of strategy, achieve the desired effect with a combination of git format-patch and git apply/git am First, when the branches are identical, in development, remove all unnecessary files but keep the structure. Start working on the files you want.

When the changes are ready to go to master, let's say you have made 5 commits by then. Execute something like:

git format patch -5 --stdout > /some_folder/patchname.patch

Now you can checkout master and apply the patch you created in /some_folder/patchname.patch using something like

git am --signoff < /some_folder/patchname.patch

first you might wanna check if everything will be fine by running:

git apply --check /some_folder/patchname.patch

Another way is to use git cherry-pick (see https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html) to manually choose what commits you want to transfer between both of branches.

Hope this helps in any way.

like image 190
MythWTS Avatar answered Oct 18 '22 15:10

MythWTS