Rene Groeschke
Rene Groeschke

Reputation: 28653

Apply git merge stategy only on one file?

When merging a branch into another, it is possible to define the merge strategy like

git merge release -X ours

This applies the strategy "ours" globally when merging stuff from the release branch into the current branch. Is it possible to apply this strategy only on one specific file like

git merge release -X docs/release-notes.md ours 

so that the "ours" strategy is only used when merging docs/release-notes.md file? Or is anybody aware of another option to achieve that?

Upvotes: 6

Views: 1290

Answers (3)

jakub.g
jakub.g

Reputation: 41238

I answered a very similar problem in this answer

Using a wrapper around git-merge-file that I proposed there, you could do the thing you want with

git merge release 
git-resolve-conflict --ours docs/release-notes.md

Here is the wrapper bash function that I wrote:

git-resolve-conflict() {
  STRATEGY="$1"
  FILE_PATH="$2"

  if [ -z "$FILE_PATH" ] || [ -z "$STRATEGY" ]; then
    echo "Usage:   git-resolve-conflict <strategy> <file>"
    echo ""
    echo "Example: git-resolve-conflict --ours package.json"
    echo "Example: git-resolve-conflict --union package.json"
    echo "Example: git-resolve-conflict --theirs package.json"
    return
  fi

  git show :1:"$FILE_PATH" > ./tmp.common
  git show :2:"$FILE_PATH" > ./tmp.ours
  git show :3:"$FILE_PATH" > ./tmp.theirs

  git merge-file "$STRATEGY" -p ./tmp.ours ./tmp.common ./tmp.theirs > "$FILE_PATH"
  git add "$FILE_PATH"

  rm ./tmp.common
  rm ./tmp.ours
  rm ./tmp.theirs
}

Upvotes: 1

JosefAssad
JosefAssad

Reputation: 4128

git merges operate on different states of the tracked content, not on individual files. Rephrasing, git does not see any fundamental difference between a commit touching two files or a commit touching one file.

There is therefore an expectation in a clean git workflow that there is a thematic coherence in commits and branching strategies. More specifically, it's more "gitty" to produce a commit that fixes a "subject" than a commit that fixes a specific file. It's more "gitty" to have branches that contain work done towards specific "topics" rather than branches addressing the development of specific files.

Relating this back to your question, without knowing too much about your codebase or git strategy, it's possible that the need to merge a specific branch differently according to the state of individual files indicates that the branching model might need a bit of polishing.

If you want the changes in the release branch but not the changes in the README.md file in the release branch then it's possible that the changes in README.md from release might need to be split out somehow so you can merge the release branch without merging changes to README.md. However given that the branch is called release I imagine you don't want to bang on it very hard at all.

If your need to merge from release but ignore README.md changes is recurrent, you might consider setting up a parallel branch to release like release-noreadme. Then you can bang on release-noreadme all you want, including massaging the README.md file to suit your needs, such that you can then merge from release-noreadme without worrying about tiptoeing around specific changes in specific files.

tl;dr: consider having a branch synced to release where you can iron out unwanted changes, then merge from that branch instead of release.

Upvotes: 1

gipi
gipi

Reputation: 2515

I don't think this is possible, if you look at the help

       ours
           This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree
           that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken
           from our side.

           This should not be confused with the ours merge strategy, which does not even look at what the other tree contains at
           all. It discards everything the other tree did, declaring our history contains all that happened in it.

you can see there is no indication of options available, instead of subtree strategy where it's possible

       subtree[=<path>]
           This option is a more advanced form of subtree strategy, where the strategy makes a guess on how two trees must be
           shifted to match with each other when merging. Instead, the specified path is prefixed (or stripped from the beginning)
           to make the shape of two trees to match.

Upvotes: 1

Related Questions