MHebes
MHebes

Reputation: 3197

How do I auto-format master and feature branches without causing conflicts?

Say I have this git history:

* 894a016 (HEAD -> feature) Add radius() method
* 6a62db6 (master) Add circle.h

Where circle.h in feature looks like:

#include <iostream>
using namespace std;

class Circle {
  double radius;

public:
  Circle(double r)
            : radius(
                r) {
  }
  double area() {
    return radius
          * radius
          * 3.14159265;
  }

  double radius() {
      return    radius;
  }
};

I want to format my entire repo, master and feature branches, without causing too many conflicts.

I can make new commits to any branch, but ideally would not need to rebase feature branches (if this is the only way that's fine—I'm doing this for a team so I'm just trying to keep things as painless as possible).

How do I format my trunk branch and my feature branches without creating unexpected conflicts?

Formatting both branches does not work, for example:

* 2e654d8 (HEAD -> feature) Run clang-format
* 894a016 Add radius() method
| * 25fab84 (master) Run clang-format
|/
* 6a62db6 Add circle.h

Results in conflicts when trying to merge. For example, git checkout feature && git merge master gives this conflict:

#include <iostream>
using namespace std;

class Circle {
  double radius;

public:
  Circle(double r) : radius(r) {}
  double area() { return radius * radius * 3.14159265; }
<<<<<<< HEAD

  double radius() { return radius; }
=======
>>>>>>> master
};

Upvotes: 0

Views: 344

Answers (1)

MHebes
MHebes

Reputation: 3197

I think I found an acceptable answer. This works for this toy example, I'll do more tests and see if it works on a larger scale.

Given this (slightly more complex) history:

* c9ede4f (master) Add area to print()
| * c859a1d (feature) Add radius to print()
|/
* 58ead7c Add print()
* 427a8ba Add circle.h

(this particular history actually gives good conflicts when formatting all branches, but I believe this solution works in the general case)

  1. Auto-format master (tag the commits before and after formatting for ease)

    $ git checkout master
    $ git tag before_auto_format
    $ clang-format -i *
    $ git commit -am "Run clang-format"
    $ git tag after_auto_format
    
  2. Merge the pre-format master into feature and resolve conflicts like normal

    $ git checkout feature
    $ git merge before_auto_format
    $ vi circle.h
    $ git add .
    $ git commit
    
  3. Merge after_auto_format into feature. Discard the changes and do the formatting manually.

    $ git merge after_auto_format --no-commit
    $ git checkout HEAD .
    $ clang-format -i *
    $ git add .
    $ git commit
    

The final history looks like:

*   09f2448 (feature) Merge tag 'after_auto_format' into feature
|\
| * e5e964b (tag: after_auto_format, master) Run clang-format
* | 1ef1b9b Merge tag 'before_auto_format' into feature
|\|
| * c9ede4f (tag: before_auto_format) Add area to print()
* | c859a1d Add radius to print()
|/
* 58ead7c Add print()
* 427a8ba Add circle.h

I believe this achieves the desired effect of syncing the feature branch with the trunk, auto-formatting both, and not causing unexpected conflicts.

If anyone has better alternatives, I'm all ears.

Upvotes: 0

Related Questions