Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git - How to selectively apply changes from one branch to another?

Is it possible to selectively apply changes from one branch to another with Git?

More specifically, I use a public dev branch for GitHub and a private master branch for deployment. When changes are made to one branch they will need to be applied to the other, but some lines of code need to stay different. In my case it's a few css classes and a feed.

I'm new to Git but I've made my research :

  • git merge --no-commit --no-ff can be used followed by a git mergetool to chose what I want in case of a conflict. The problem is that it only works for conflicts Git can't automatically merge, so what I want to stay different gets replaced before I get the chance to use my mergetool.

  • git difftool --cached is useful as it allows me to see the differences, but I need to copy what I want to keep from there and manually replace it with a text editor, as I cannot simply choose and save like I can with mergetool.

  • git cherry-pick seems to apply a specified commit to another, but what I want to stay different may be scattered to different commits, and these commits may not only include what I want to stay different. I cannot see this working unless I make millions of commits that would drive me mad.

Also to be clear, I don't want one branch to become another, what seems to be the case with a merge. I want two separate branches with their respective differences and apply changes from one to the other.

Is there a better workflow that would allow me to keep a development and a deployment version by applying their changes and keeping a few differences? I don't mind using separate repositories or different tools if it leads to a solution.

like image 347
toucanb Avatar asked Mar 13 '14 01:03

toucanb


People also ask

How do I select changes from one branch to another in git?

In the Branches popup (main menu Git | Branches), select the target branch that you want to integrate the changes to and choose Checkout from the popup menu to switch to that branch. Open the Git tool window Alt+9 and switch to the Log tab. Locate the commit containing the changes you want to cherry pick.

Which command used to integrate changes from one to another branch?

The "merge" command is used to integrate changes from another branch.


2 Answers

I've also found out about patching :

To create the patch : git diff dev > master.patch

To apply it : patch < master.patch

like image 151
toucanb Avatar answered Oct 20 '22 18:10

toucanb


Take advantage of the fact that creating git branches is cheap and need have no effect on the actual content of the working directory.

  1. Check out your source branch dev.
  2. Create a temporary branch. It will point to the same commit that dev does: checkout -b for_master

    Presumably, you know (or can easily find out) which commit before the dev branch is the last one before the changes you (partially) want. In this example, let's say that that commit has the hash 1457B4 ('last before', get it?).

  3. Reset your for_master branch to that commit: git reset 1457B4. (Do not use the --hard switch!)

    Now, you have a working directory containing all the changes that are in dev, but from the POV of the for_master branch, those changes are unstaged and uncommitted (while the dev branch still points to commits that record all the changes, so the work is still safe).

  4. Using interactive staging (git add -p and/or git add -e), create a commit (or more than one, if you like) that contains all, and only, the changes you want to apply to your master branch.

    Make a note of the hash of the last commit (or give it a tag). In this example, I'll say that its hash is C0DA.

  5. Check out master.

  6. Cherry-pick the commit(s) you just made: git cherry-pick 1457B4..C0DA.

    (Note that cherry-picking a range is only available after git version 1.7.2. Otherwise, you'll need to individually cherry-pick all the commits you made in step 4.)

    (Also note that when you cherry-pick a range, the start of the range is the commit before the first one that will actually be picked.)

This process is kind of the inverse of using git checkout -p as mentioned in the selected answer. It might be useful for creating cherry-pick-able commits between two branches that share some code but also have a lot of differences (e.g. between two major versions of a project), and you don't want to have to spend a lot of time ignoring irrelevant files in a call to git checkout -p.

Personally, I've found it convenient to use two different worktree directories for the same repository (one for the source branch and one for the destination) and switch between two command shells, one using the source branch directory (worktree) and the other the destination. But if you aren't comfortable using the git worktree feature, that might not be for you.

like image 26
Wilson F Avatar answered Oct 20 '22 18:10

Wilson F