Search code examples
gitgit-tower

Merging only certain changes from one git branch to another


Say I have a git repository with two branches - main and custom. Say that I'm working in custom and I make two changes to the file print.php:

/* begin custom only change */
echo "I'm only printed in the custom branch version";
/* end custom only change */

echo "I want this printed in both branches";

Say also that meanwhile, I've pulled a new main branch copy, and it has the following change to print.php:

echo "This should also be printed in both branches";

What should I do -- either with the command-line or with a git program like Tower (or even suggestions for making a custom script) -- in order to have the following resulting files?

print.php in main branch

...
echo "I want this printed in both branches";
echo "This should also be printed in both branches";
...

print.php in custom branch

...
/* begin custom only change */
echo "I'm only printed in the custom branch version";
/* end custom only change */

echo "I want this printed in both branches";
echo "This should also be printed in both branches";
...

Obviously the order of the echo "I want this..." and echo "This should also..." is not something that Git can figure out, so there's going to be some manual decision-making here. But I want to know how to do it in the most "Git" way possible and involving the least number of error messages from a program like Tower.


Solution

  • So the way I understand it, you have 2 changes in custom, only one of which needs to be merged into main, and one change in main that needs to be merged into custom. You can solve your issue this way:

    • rewind custom to before the 2 changes
    • add the one change to custom that you will want to merge into main
    • stash the second change
    • merge the one commit from custom into main, resolving merge conflicts
    • merge the changes from main into custom
    • pop the stashed change in custom, and commit it

    If you've already committed the 2 changes in custom, you'll need to first do git reset --soft [hash-of-the-commit-before-new-changes] (you can find the hash for the correct commit with git log). Otherwise, just proceed as below.

    You can do line by line commits in interactive git add mode:

    git add -p print.php
    

    In this mode, stage this change first, by itself:

    echo "I want this printed in both branches";
    

    (Once in interactive mode, if you hit "s" git will attempt to split commit hunks into smaller hunks for you. "y" will stage a hunk for commit, "n" will skip it. If "s" doesn't work it's magic, hit "e" and manually edit the hunk. More info)

    Once that's staged,

    git commit
    git stash            # stash unstaged, uncommitted change in custom for later
    

    Then,

    git checkout main    # get in main branch
    git merge custom     # merge custom, you'll probably get a merge conflict
    

    If/when you get a merge conflict:

    git mergetool
    

    I am able to tell git to keep lines from both versions of the file and choose either left or right to appear first in the file.

    git commit           # commit this change to main
    git checkout custom  # get in custom branch
    git merge main       # merge main
    

    Then,

    git stash pop        # pop that other change to custom out of the stash
    git add print.php    # stage it for commit
    git commit           # commit that second change to custom
    

    It's ugly... but it works.