1

One of the more difficult things to do reliably in Git right now is merge the latest changes to a set of files from one branch to another. The changed files in question have been modified across several various commits in the branch and each commit containing these changes may also have changes to other files not relevant to this merge.

The quickest way I can see to do it is this:

$ git checkout master
$ git checkout topic1 -- *.vcproj *.mk Subdir/SomeFile.txt
$ git add .
$ git commit -m 'Merging latest changes to these files from topic1'

The 2nd step would be to somehow rebase/squash/etc topic1 to clean it up and remove any changes to the files I moved to master. What is an efficient workflow for this?

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • So you want to "merge" only a set of files, and not the entire branch? – Raul Rene Mar 10 '14 at 21:51
  • @RaulRene Correct. The reason for this is that I've collectively made a bunch of changes unrelated to the feature that my topic1 branch is responsible for. Only just now realizing this, I'd like to move that work to `master` so that it doesn't create unnecessary merge conflicts and rebase time for me. The changes aren't isolated to single commits, so that's what makes this less straightforward than I like. – void.pointer Mar 10 '14 at 21:55
  • You might want to look into `cherry-pick -n` (without commit), that lets you revise your cherry-picked files before making a new commit. In this way, you can drop changes to files you don't need while maintaining the ones you care about. See [this question](http://stackoverflow.com/questions/1526044/partly-cherry-picking-a-commit-with-git) and [this one](http://stackoverflow.com/a/5717615/1300817) for similar examples – Raul Rene Mar 10 '14 at 22:06
  • It's unfortunate you've been downvoted so much. Sometimes real world requirements get in the way and the need for this arises, such as backporting only a specific set of features in some files to an older release, where those feature implementations have been spread over multiple commits. – ray Mar 04 '15 at 15:05

3 Answers3

1

If you have unrelated commits, perhaps you should set up new branches for each separate real topic, starting at the branch point. Then go through the history of your messed up branch, and git cherry-pick each commit to it's right place. Once you have verified no changes got lost, get rid of the mess.

vonbrand
  • 11,412
  • 8
  • 32
  • 52
  • 1
    This works if the unrelated changes are isolated to commits. However in my case, changes to the relevant set of files is spread across commits. So I'd either have to split the commits (very complex and time consuming) or simply do the `git checkout -- `. Good answer though, +1 – void.pointer Mar 17 '14 at 14:44
1

I was expecting some magical fix to this problem but unfortunately there is not one. The easiest fix for this is to simply do git checkout -- <file> for each file that is modified. You then have the new changes on another branch. You have lost the history, but you can type a new one if needed (think of it like doing a squash).

This article goes over the attempted solutions and realization that git checkout is ultimately the most practical solution when in this situation.

The steps are:

git checkout master
git checkout topic1 -- *.vcproj *.mk Subdir/SomeFile.txt
git commit -m 'Merging latest changes to these files from topic1'

I don't think the git add is necessary after checking out the specific files from topic1 since I've noticed they are automatically added to the index.

void.pointer
  • 24,859
  • 31
  • 132
  • 243
-1

The problem is not the need for selective merging, its the fact that you have different things on the same branch to begin with. The real answer to clean up this workflow, is to stop working like this and make new branches often. Things happen, but you shouldn't need to do this sort of thing regularly enough to need a special workflow for it.

The whole point of a branch is that its a discrete set of changes that can be merged it. If you're working on something different, make a new branch, even if its just a branch based on the current one.

That aside, I think you're fix is about a simple as its gonna get. The only other way I could think of doing this would be the following.

git checkout master
git merge topic1
git reset --soft master
git add -i .

This is actually more steps than yours, but the use of interactive adding might make it a little easier to do since you can get as granular as splitting individual hunks in the same file. However, you will lose all connected history to the other branch.

I can't stress enough, the real answer is to adjust your workflow so this sort mixed-purpose branch never happens. The only possible exception were if you could isolate your different purposes into different directories - then you could use git-subtree-split, but thats not your situation it seems, so I won't go into that.

eddiemoya
  • 6,713
  • 1
  • 24
  • 34
  • I'm working on a very large feature. It will be a few weeks until it's done. It's not reasonable to expect people to know in advance when a particular task could be separated, especially when considering changing requirements and refactoring, among other things. For the times that this happens, while not often, I want a way to go back and fix it. GIT should be more than capable of easily doing this, especially for local branches. I understand your suggestion and the general philosophy, but mistakes happen. – void.pointer Mar 11 '14 at 01:17
  • Mistakes are one thing, but your plan/workflow should not encourage mixed-use branches. You don't need to know much ahead of time. I've worked massive features before. You can tag when your at important stopping points, branch out when your experimenting. Thats the better practice. – eddiemoya Mar 11 '14 at 16:22
  • You can split up history, with subtree split, like i said - but that only splits up specific directory paths, it wont be able to cherry-pick specific files or use any kind of regex. – eddiemoya Mar 11 '14 at 16:24
  • As far as cherry picking files from different branches, I don't think its gonna get much easier than what you are already doing, except perhaps the way I suggested - but its really a matter of preference between the two. – eddiemoya Mar 11 '14 at 16:32
  • I think you still misunderstand. You can't argue branching philosophy when you don't understand the context of why I'm in this situation to begin with (which isn't because I wasn't following those principles). That's why I don't want to argue over it. Just because I learn how to recover from this doesn't mean I'm giving myself an excuse to let it happen again. I don't know why anyone would want to do things this way on purpose, it's a big pain in the ass. – void.pointer Mar 11 '14 at 18:09
  • Im not arguing philosophy. I'm explaining why your having this problem, and how to prevent it. If you can't do things the right way for some reason, thats ok - just understand there is a better way to do things and when it is possible (which should be most of the time) then go for it the better way - im just explaining what that better way is. As far as how to solve the problem as a one-off circumstance. I've also explained, the way you are already doing it is about as easy as its going to get, I've also provided an additional way to do it which might be slightly easier. – eddiemoya Mar 11 '14 at 19:37
  • And we have to go back to square one: I'm not asking about *why* I'm in this situation. I'm asking how to get out of it. And what you're talking about is best practice, which I'm already aware of. Again I didn't go into the details of why I"m in this situation but unfortunately best practice wasn't the solution. – void.pointer Mar 17 '14 at 14:41
  • Your questions asks how to easily merge selective files. I've explained that you're already doing that correctly (as correctly as is possible), and offered one alternative you might find preferable. Yes, I explained best practices (which is important even if you already know them, because others will read this page), but I also answered your question about the merge. I don't understand why you are fighting with me on this. If you simply don't believe I'm correct, thats another thing entirely, but I have responded to your direct question. – eddiemoya Mar 17 '14 at 15:55