Let's say I have a feature (topic) branch that I keep rebased on top of my development branch. During the course of the project (before merging in my feature branch), I decide that I need to make a large refactor to my project (for example, after updating a 3rd part module).

So I do this large refactoring on my development branch. Now I want to rebase my feature branch so I can take advantages of my refactoring.

The problem

There are still things in my feature branch that need refactored to match the changes I made in my development branch.

Should I:

Go back through my feature branch's history trying to edit commits (with rebase -i) to make the branch look as though all of the work had been done after the refactoring.

The advantage to this is that it keeps the history clean.

The disadvantage is that this can take a whole lot of time if the changes made in the development branch cause a lot of changes to need to be made in the feature branch.

Fix the things that need to be refactored in my feature branch and make a commit for this.

The advantage here is that it will be much easier to identify and fix things that need to be fixed

The disadvantage is that now the tree will have two commits in it for the refactor. One for the refactor done for the entire development branch, and a smaller commit done for the feature branch, once merged in it will look a little funny.

Which strategy should I go with?

An Example

Lets say on the development branch I rename functionA to functionB.

Now In my feature branch I've never modified the file containing functionA (now functionB in development). So when I run rebase development while on my feature branch it rebases cleanly.

The problem is if I've ever made a call to functionA in my feature branch, it's going to fail now since it was renamed functionB.

Now, should I just do a find and replace for functionA -> functionB and make one commit on the feature branch (option 2). Or should I go back through my history, finding where I introduced the call to functionA and rewrite the commit so it is introduced as calling functionB (option 1)?

4 Answers
4

Option 1 sounds like a lot of unnecessary work. Why do you wan't to hide the fact that this code was written before the refactoring of dev?

Another disadvantage with option 2: After the rebase you will have a lot of possibly non-working commits before the 2nd refactoring commit. This will give you problems when bisecting since those commits might be untestable.

Option 3: Merge dev branch into feature branch.

Pro: you will get the rectoring from dev and may refactor the rest of the feature branch in the merge to get a working project.

Pro: No commit gets untested. (assuming the commits already made is tested).

It seems that the git revolution has created a new neurosis called commit history anxiety. No one besides you cares what's in your commits. Just get the work done as efficiently as possible. Then you can use the time you saved to fix a bug or add a feature.

I know at least two use cases that benefit significantly from organizing the commits in logical steps. One is searching for causes of regression by interval halving (git bisect), the other is using commit logs to track notes about code (to avoid reintroducing old bugs, you need to look at history of code in question, but it only works well if the steps are logical and described).
–
Jan HudecJan 24 '13 at 8:05

Not sure why you would do a rebase -i. I would just do a rebase, and fix the problems as they come in you feature commits.

I find fixing one and one commit is easier than fixing every error afterwords. You can then also make sure, between each commit, that your tests still runs (given that you have tests that is).

Lastly, I find 2) to be problematic if you plan to continue rebasing in the future, if your feature is not yet done. Rebasing in a merge is really not something I would do if I could avoid it. If the feature is done and you don't care to much about history however, you could just merge.

Conclusion:
I would personally rebase, without the -i, and fix each commit. The reason is that I find a tidy log quite useful, and I often feel that it is the easiest way to do it.

EDIT: By your example, I would say it depends. If there are a huge amount of commits, you have called functionA a lot of times, and it basically is a huge pain to rebase every single commit, I would probably fall back to just do a search-replace in a single commit. If I knew there were only a few places, and the rebasing would be easy, I would rebase.

Since you ask, I guess the former is the situation you are in, and I would have though about how much pain will it be to clean up the log.

Sorry I think my question needed an example. See the updated OP. Making a merge commit is out of the question (and I never really considered it an option) precisely for the reason you described.
–
Evan PurkhiserJan 24 '13 at 17:17

Indeed I see this as the decisive reason why Feature Branching is a bad idea. Once a team is afraid to refactor to keep their code healthy they are on downward spiral with no pretty end.

In the quoted text, Martin Fowler is using 'Feature Branching' specifically to mean 'using dvcs branching to manage large-feature development in a way where one dvcs branch maps to one feature'. Which lots of people do. Some of those people are in an environment where they never really need to refactor anything, some of them haven't been doing it long enough to hit the problems, a few have developed tools or procedures on top of git to work around the problems (http://dymitruk.com/blog/2012/02/05/branch-per-feature/), while others are simply in denial as to how much trouble it is causing them.

Thing is, just because an abstract concept and a tool feature have the same name doesn't make them a good match for each other. As you are finding, there isn't really a good way to use the two together, just a variety of less-bad ways.

So, assuming you do really need feature branches, then look through the features your tooling and platform support and find a better match.

Sticking with git, using forks and pull requests is one increasingly common strategy:

yes, it is a very common mistake to use git 'branching' on 'features' to do 'feature branching'. Names can mislead: it used to be a very common mistake to use a 'goto' statement to 'go' from one block of code 'to' another...
–
soruFeb 18 '13 at 12:33