Search code examples
gitrebasegit-rebaseprettier

how to rebase when prettier formatting was applied to whole project


Someone merged in prettier formatting changes across the whole codebase into our master/main/develop branch.

I am now trying to rebase against latest master/main/develop branch, and resolve merge conflicts.

Since the conflicts are simply caused by running prettier to format code, is there a way to resolve conflicts automatically while preserving commit history? (no new merge commits, no extra formatting commits)


Solution

  • ProTip™️ Ensure all TeamMates have resolved conflicts for all WIP branches before the prettier mass formatting changes are merged! ✨

    Once everyone resolved conflicts for their WIP branches ✅

    Merge the prettier formatting changes on latest master 🙏

    Come back here to auto-resolve formatting conflicts! 😁

    Preparation:

    Ensure you have the NEW version of prettier installed in your node_modules:

    git checkout master
    git pull
    yarn install
    git checkout $FEATURE_BRANCH
    

    Now, go to your master branch, and find two commit shas, put this in a notepad:

    # 1. Commit where mass formatting was applied:
    export MASS_FORMAT=0r93y82q9afuwiehojpei90ur38qy2huia
    # 2. Commit just before that one (with updated prettier version + settings, etc):
    export BEFORE_MASS_FORMAT=0ury810r8y32hquofawjp08hru3o2wafij
    

    Now, you must ask yourself: Did your branch have merge conflicts before the prettier mass commit?

    If you are certain the answer is "no" you can skip step 1.
    To be extra safe, and gain experience with rebasing, just do step 1.

    1. Resolve conflicts for changes before mass formatting commit:

    Additionally, look at the history on your $FEATURE_BRANCH, and determine the last sha from master that is in your feature branch. This is called the "fork point" or "merge base", I'll refer to this sha as the $BASE_SHA. (The first commit of your PR is the branches "FOOT", as opposed to your branches HEAD. Just before FOOT would be your $BASE_SHA.)

    Rebase one: Ensure no conflicts before mass formatting changes were applied:

    git checkout $FEATURE_BRANCH
    git rebase --onto $BEFORE_MASS_FORMAT $BASE_SHA
    

    Resolve conflicts throughout the rebase normally.

    2. Let's auto-resolve those formatting conflicts!

    FEATURE_BRANCH=`git branch --show-current`
    git checkout $MASS_FORMAT &&
    git pull &&
    yarn install && # pickup new prettier version
    git checkout $FEATURE_BRANCH &&
    git rebase \
      --strategy-option theirs \ # This is flipped, means "keep my feature branch changes"
      --empty=drop \ # Probably related to formatting.
      --exec "$(echo \
          'yarn prettier --write ' \
            'package.json ' \
            '$(git diff HEAD^..HEAD --name-only) ' \
          '|| echo prettier failed its ok; ' \
          'git add . ' \
          ' && git commit --amend --no-verify --no-edit' \
        )" \
      --onto $MASS_FORMAT $BEFORE_MASS_FORMAT;
    

    package.json is listed in the --exec call, so that prettier won't decide to just format all files.

    3. Finally, run a normal rebase against latest master:

    git pull origin master:master --rebase
    

    If you are weary about force pushing, inspect diff:

    git diff origin/$FEATURE_BRANCH
    

    If the diff is too big and include unrelated changes from master... you can use range-diff:

    git range-diff $BASE_SHA..origin/$FEATURE_BRANCH $BASE_SHA..$FEATURE_BRANCH
    

    And lastly, push up cleanly formatted history:

    git push --force-if-includes --force-with-lease origin master:master