2

I am new to git (and version control in general) and I'm trying to work out how best to implement my workflow. I'm working on a (personal) project that involves a lot of "permanent" branches, i.e. completely separate programs that are forked from a common code base and will never be merged into a master branch. (This is because I'm a scientist working on a simulation model, and I'm trying out a lot of new things just to see if they have interesting results. If they do, I currently copy the whole project folder so that I can come back to it later. I'm aiming to use git branches for this purpose instead.)

Because these branches are permanent, I want to know if there's an easy way to take a feature that I've implemented in one branch and transfer it to another, while preserving the differences between the two branches. For example, suppose my repository's tree looks like this:

               model_a
              /
initial commit 
              \
               model_b

In my case, model_a and model_b are using broadly the same simulation code to model two different things. They might differ in the values of some parameters and/or some details in the inner loops of the simulation code, but the general "infrastructure" surrounding it will be the same. Now, while working on branch_a, suppose I implement a new way of visualising the results:

               model_a --- model_a_with_visualisation_code
              /
initial commit 
              \
               model_b

What I want to know is, is there a git command I can type that, barring merge conflicts, will result in this:

               model_a --- model_a_with_visualisation_code
              /
initial commit 
              \
               model_b --- model_b_with_visualisation_code

In other words, I want to take just the commits that were used to turn model_a into model_a_with_visualisation_code, and apply copies of those commits onto the end of the model_b branch. Or at least, I think that's what I want.

It looks like git rebase should be the tool I want, but I'm having a hard time getting my head round it, and I can't find any examples that illustrate this use case. It also seems that git rebase deletes the old versions of the commits, rather than making copies of them.

I hope the question is clear. As I said I'm new to git and a lot of the main concepts are still a bit hazy for me. For example, I'm not entirely sure whether the labels in the above trees are meant to be tags or branches or just commits. If I've misunderstood how something is supposed to work, I'd appreciate any clarification.

N. Virgo
  • 7,970
  • 11
  • 44
  • 65
  • This is called [cherry picking](https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html) – 1615903 May 21 '13 at 09:17

3 Answers3

3

Yes, it's possible (see other answers), but I feel that you might try to solve the wrong problem.

Instead of diverging on your models, it might be a better idea to structure your simulation code in a way that you can easily switch between the different models, while keeping the library with all surrounding code and visualization shared.

You can still branch off when starting to build a new model, but it might be advantageous to merge all that code back together so that in the end, you have a single simulation where you can choose just the models that you want for that run.

Otherwise, after some time, you will have a large set of slightly different branches that all contain different bugs, and where you (probably) don't really know anymore which is which.

Wilbert
  • 7,251
  • 6
  • 51
  • 91
  • Yeah, I know, that would be the proper way. But I am a scientist, not a programmer, and there is a tradeoff between learning to structure a large code base in a way that won't need serious re-working later on (something that's happened all too often in the past), versus learning a tool that will let me keep doing it the quick-and-dirty way, only more efficiently. And this way I can absolutely guarantee that later changes won't change earlier results. I'm sympathetic to what you say, but for me personally, at this moment in time, I think the quick and dirty way is the right choice. – N. Virgo May 21 '13 at 10:01
  • You will regret this decision, but it is yours to make :). Just being able to run different models / simulations again without much hassle, to extract whatever data you need at that point is invaluable. – Wilbert May 21 '13 at 10:06
2

cherry_pick is used to apply changes introduced by some existing commits. By specifying git cherry_pick [branch] you should commit the commit at the tip of the specified branch in the current branch you are in.

git checkout model_b
git cherry-pick model_a

Documentation

Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
  • `git: 'cherry_pick' is not a git command. See 'git --help'. Did you mean this? cherry-pick` :-) – krlmlr May 21 '13 at 09:23
  • @krlmlr Thanks for pointing that out, I was just writing some sql a minute ago, must have carried over... – Kevin Bowersox May 21 '13 at 09:25
  • I tried this on a "toy" repository, but it came back with merge conflicts from the differences between `model_a` and `model_b`. Perhaps it should have been `git cherry-pick model_a_with_visualisation_code` instead? I would try it but git now won't let me do anything without first resolving the merge conflict - I don't know how to tell it to ignore what I just tried to do. – N. Virgo May 21 '13 at 09:30
  • @Nathaniel from model_b: `git reset --hard ORIG_HEAD` See: http://stackoverflow.com/questions/2389361/undo-a-git-merge – Kevin Bowersox May 21 '13 at 09:33
  • `fatal: ambiguous argument 'ORIG_HEAD': unknown revision or path not in the working tree.` – N. Virgo May 21 '13 at 10:04
  • after some googling, `git reset --merge` did it. I have to dash now, I'll come back to this later. – N. Virgo May 21 '13 at 10:07
  • This worked after a quite a bit of learning how to structure the repository in the right way. My mistake previously was to type `git branch my_branch` *before* making a new set of changes, instead of after the fist commit. I can see it isn't going to be easy to implement the workflow I want, but at least I can see how it will be possible. – N. Virgo May 24 '13 at 21:21
2

Kevin's answer is correct, and it's a good way to do it if this is occasional. But, if you expect to get a lot of these changes, I find that constant cherry-picking is a PITA. I would suggest that you create yet another branch, called for example common. Code that should get into both branches goes here, and gets merged to the model_a and model_b:

model_a:          E->F->K
                  /     /
common: A->B->C->D---->I
                  \     \
model_b:          G->H->L
Community
  • 1
  • 1
1615903
  • 32,635
  • 12
  • 70
  • 99