views:

70

answers:

5

This happens often in my work flow: I'm working on a feature in a separate branch, and while doing this I'll come across small things that need fixing but are from higher up in the framework or site layout for example.

I want to switch back to the main develop branch and commit changes from select files there, then go back to a feature branch, and rebase so that I can continue there with the unrelated tweaks/bugfixes out of the way.

I'm using git stash and git stash pop to do this, but I'm getting a lot of conflicts from a bunch of files I modifed but don't need to be committed to the parent branch anyway.

Is there another way to avoid conflicts or somehow save the current state, and only pull select working tree changes to another branch for commiting ? (sort of like git-stash-cherry-pick ;-))

A: 

What about creating a temporary branch?

Something like:

- oh crap need to do somethning else now
- git checkout -b ResumeLater
- git add .
- git commit
- git checkout ImportantStuff
- ....
- git checkout ResumeLater
Let_Me_Be
Hi, I don't think this will work. My problem is I have improved or resolved a bug in, say, a API call in "files.c", while working on new feature in branch "feature" that made the API tweak necessary. I have 20 modified files now in my branch, but I want to bring only files.c back into the parent "develop" branch. If I stash and pop, I get a bunch of conflicts from all modified files. Ideally, what I need is to "git stash pop <file>" so I can take out the changes only for the file I want to commit on my base "develop" branch.
faB
I guess I could commit selected changes like that, then commit the rest, then cherry pick the selected changes. But that still leaves the selected changes into the feature branch. What I want to do is take them out of there, put them in the parent branch, and rebase the feature branch on it. So in the feature branch there are only commits for feature and not API/framework changes and such. I guess basically I'm just trying to keep my commits clean and focused.
faB
+2  A: 

I usually do it the other way around. I continue working in my feature branch until I'm ready to make a commit there. As soon as I am, I add all changes that belong into the new commit for the branch to the index, but not those that belong into master. git add -p et.al make that really easy. Once all relevant changes in the index, I commit to the branch. All remaining remaining dirty changes belong to master and will be carried along just fine once I switch to that so I can commit it there.

rafl
That's an interesting workaround. You don't get errors when switching branch because it's in the index then?
faB
I should have mentioned I like the rebase method because whenever I merge a branch I know there will be no conflicts (the feature branch is always on top of the main one, ie "fast forward"). That's why I want to commit selected changes onto the main branch, then rebase feature branch. I guess typing this made me realize it won't happen without commiting the changes first. It's just I used to be able to *git checkout* with uncommited work to do this easily; but recently I'm getting a lot of errors and git won't even allow me to checkout to another branch, and I can't see the pattern behind it.
faB
You'll get errors if the dirty changes you have don't apply to the branch you're switching to. But chances of that happening seem to be slim. One can usually tell from a diff chunk if it's intended for only the feature branch you're working on, or if it fixes more general things. If you don't have any changes related to the branch anymore, things will usually end up being fine. This seems to be a good enough solution for most things, especially considering that feature branches tend to be short-lived and often rebased on master, so the diversion outside of the features scope is usually minimal
rafl
I don't like this since it prevents you from checking in the 'master' changes. Git was invented to solved the "not ready to check-in" syndrome.
Casey
+1  A: 

On MacOS, GitX makes it very easy to do the kind of selective committing rafl describes, so that's a good way to approach it if that's the environment you're in.

It's also possible/practical to commit branch-y changes and master-y changes in separate commits, then use git format-patch to export the commits from the branch as files and git am to pull them in to the master.

The danger here is if the files around the changes are too different, in which case there may be conflicts when pulling the commits in to the master.

pjmorse
`git-gui`, which happens to be part of git itself, also provides that functionality in a GUI, and in a cross-platform fashion. Using `format-patch` and `am` to apply commits from one branch to another seems very odd though. This is what `git cherry-pick` is for.
rafl
Good points all, thanks for the expansion.
pjmorse
GitX is awesome, use it all the time. It's true it helps a lot making selective commits.
faB
+1  A: 

Try switching back to master branch using --merge option. It will try to do a three way merge between the two branches. The git documentation has a good example:

2. After working in the wrong branch, switching to the correct
   branch would be done using:

      $ git checkout mytopic

   However, your "wrong" branch and correct "mytopic" branch
   may differ in files that you have modified locally, in which 
   case the above checkout would fail like this:

      $ git checkout mytopic
      error: You have local changes to 'frotz'; not switching branches.

   You can give the -m flag to the command, which would try a
   three-way merge:

      $ git checkout -m mytopic
      Auto-merging frotz

   After this three-way merge, the local modifications are not
   registered in your index file, so git diff would show you what
   changes you made since the tip of the new branch.
Casey
Yeah I was a bit worried of using that and ending up with nasty merges. But your previous answer works great and does not require to checkout with a "dirty" working tree. It's great also to be able to commit small changes that belong on the master branch, when you just did them, in logical order.
faB
+2  A: 
  1. Commit the changes that you want in master on your current branch.
  2. Stash your remaining changes
  3. Switch to master branch and use git cherry-pick to move the changes onto master
  4. Move back to your feather branch, and rebase (optional)
  5. Unstash the original feature changes
Casey
I ran a simple test and this solves the problem really nicely. I was confused as to how git would recognize the cherry-picked commit when doing the rebase. It correctly removes it from HEAD on feature branch, and moves it below the feature commits. That's exactly what I needed. Since the commit sha have changed I can only guess that after applying the master commits (and thus the cherry-picked one), git sees the HEAD commit on feature branch is already done, and does not apply it a second time?
faB
Just an update to say thanks, it works great. I did have a conflict once with cherry-pick. Since I edited it to solve the conflict, git did not remove the corresponding commit off of the head of the "feature" branch, after rebase. But I could remove it simply with `git reset --hard HEAD~1`. This maintains a linear history of commits in the main branch, and feature branch; with the latter always as a fast forward. Great.
faB