Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>On the specific instance of a config file, I would agree with <a href="https://stackoverflow.com/questions/928646/how-do-i-tell-git-to-always-select-my-local-version-for-conflicted-merges-on-a-sp/928771#928771">Ron's answer</a>:<br> a config should be "private" to your workspace (hence "ignored", as in "declared in a <code>.gitignore</code> file").<br> You may have a config file <em>template</em> with <strong>tokenized values</strong> in it, and a script transforming that <code>config.template</code> file into a private (and ignored) config file.</p> <hr> <p>However, that specific remark does not answer what is a broader more general question, i.e. your question(!):</p> <blockquote> <p><strong>How do I tell git to always select my local version for conflicted merges on a specific file ?</strong> (for any file or group of file)</p> </blockquote> <p>This kind of merge is a "copy merge", in which you will always copy 'ours' or 'theirs' version of a file whenever there is a conflict.</p> <blockquote> <p>(as <a href="https://stackoverflow.com/users/549246/brian-vandenberg">Brian Vandenberg</a> notes <a href="https://stackoverflow.com/questions/928646/how-do-i-tell-git-to-always-select-my-local-version-for-conflicted-merges-on-a-s/930495?noredirect=1#comment37608553_930495">in the comments</a>, <strong>'<code>ours</code>' and '<code>theirs</code>' are here used for a merge</strong>.<br> They are <em>reversed</em> for a <strong>rebase</strong>: see "<a href="https://stackoverflow.com/a/2960751/6309"><code>Why is the meaning of “ours” and “theirs” reversed with git-svn</code></a>", which uses a rebase, "<a href="https://stackoverflow.com/a/3052118/6309"><code>git rebase</code>, keeping track of 'local' and 'remote'</a>")</p> </blockquote> <p>For "a file" (a file in general, not speaking of a "config" file, since it is a bad example), you would achieve that with a custom script called through merges.<br> Git will call that script because you will have define a <a href="http://git-scm.com/docs/gitattributes" rel="nofollow noreferrer"><strong>gitattributes</strong> value</a>, which defines a <strong>custom merge driver</strong>.</p> <p>The "custom merge driver" is, in this case, a very simple script which basically will keep unchanged the current version, hence allowing you to always select your local version. </p> <hr> <p>Let's test that in a simple scenario, with a msysgit 1.6.3 on Windows, in a mere DOS session:</p> <pre><code>cd f:\prog\git\test mkdir copyMerge\dirWithConflicts mkdir copyMerge\dirWithCopyMerge cd copyMerge git init Initialized empty Git repository in F:/prog/git/test/copyMerge/.git/ </code></pre> <p>Now, let's make two files, which will both have conflicts, but which will be merged differently.</p> <pre><code>echo a &gt; dirWithConflicts\a.txt echo b &gt; dirWithCopyMerge\b.txt git add -A git commit -m "first commit with 2 directories and 2 files" [master (root-commit) 0adaf8e] first commit with 2 directories and 2 files </code></pre> <p>We will introduce a "conflict" in the content of both those files in two different git branches:</p> <pre><code>git checkout -b myBranch Switched to a new branch 'myBranch' echo myLineForA &gt;&gt; dirWithConflicts\a.txt echo myLineForB &gt;&gt; dirWithCopyMerge\b.txt git add -A git commit -m "add modification in myBranch" [myBranch 97eac61] add modification in myBranch git checkout master Switched to branch 'master' git checkout -b hisBranch Switched to a new branch 'hisBranch' echo hisLineForA &gt;&gt; dirWithConflicts\a.txt echo hisLineForB &gt;&gt; dirWithCopyMerge\b.txt git add -A git commit -m "add modification in hisBranch" [hisBranch 658c31c] add modification in hisBranch </code></pre> <p>Now, let's try to merge "hisBranch" upon "myBranch", with:</p> <ul> <li>manual resolution for conflicting merges</li> <li><em>except</em> for <code>dirWithCopyMerge\b.txt</code> where I always want to keep <em>my</em> version of <code>b.txt</code>.</li> </ul> <p>Since the merge occurs in '<code>MyBranch</code>', we will switch back to it, and add the '<code>gitattributes</code>' directives which will customize the merge behavior.</p> <pre><code>git checkout myBranch Switched to branch 'myBranch' echo b.txt merge=keepMine &gt; dirWithCopyMerge\.gitattributes git config merge.keepMine.name "always keep mine during merge" git config merge.keepMine.driver "keepMine.sh %O %A %B" git add -A git commit -m "prepare myBranch with .gitattributes merge strategy" [myBranch ec202aa] prepare myBranch with .gitattributes merge strategy </code></pre> <p>We have a <code>.gitattributes</code> file defined in the <code>dirWithCopyMerge</code> directory (defined only in the branch where the merge will occurs: <code>myBranch</code>), and we have a <code>.git\config</code> file which now contains a merge driver.</p> <pre><code>[merge "keepMine"] name = always keep mine during merge driver = keepMine.sh %O %A %B </code></pre> <p>If you do not yet define keepMine.sh, and launch the merge anyway, here is what you get.</p> <pre><code>git merge hisBranch sh: keepMine.sh: command not found fatal: Failed to execute internal merge git st # On branch myBranch # Changed but not updated: # (use "git add &lt;file&gt;..." to update what will be committed) # (use "git checkout -- &lt;file&gt;..." to discard changes in working directory) # # modified: dirWithConflicts/a.txt # no changes added to commit (use "git add" and/or "git commit -a") type dirWithConflicts\a.txt a &lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD:dirWithConflicts/a.txt myLineForA ======= hisLineForA &gt;&gt;&gt;&gt;&gt;&gt;&gt; hisBranch:dirWithConflicts/a.txt </code></pre> <p>That is fine:</p> <ul> <li><code>a.txt</code> is ready to be merged and has conflict in it</li> <li><code>b.txt</code> is still untouched, since the merge driver is supposed to take care of it (due to the directive in the <code>.gitattributes</code> file in its directory).</li> </ul> <p>Define a <code>keepMine.sh</code> anywhere in your <code>%PATH%</code> (or <code>$PATH</code> for our Unix friend. I do both of course: I have an Ubuntu session in a VirtualBox session)</p> <p>As <a href="https://stackoverflow.com/questions/928646/how-do-i-tell-git-to-always-select-my-local-version-for-conflicted-merges-on-a-s/930495#comment81730938_930495">commented</a> by <a href="https://stackoverflow.com/users/509565/lrkwz">lrkwz</a>, and described in the "<a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes#_merge_strategies" rel="nofollow noreferrer">Merge Strategies</a>" section of <a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Attributes" rel="nofollow noreferrer">Customizing Git - Git Attributes</a>, you can replace the shell script with the shell command <code>true</code>.</p> <pre><code>git config merge.keepMine.driver true </code></pre> <p>But in the general case, you can define a script file:</p> <p>keepMine.sh</p> <pre><code># I want to keep MY version when there is a conflict # Nothing to do: %A (the second parameter) already contains my version # Just indicate the merge has been successfully "resolved" with the exit status exit 0 </code></pre> <p>(that was one simple merge driver ;) (Even simpler in that case, use <code>true</code>)<br> (If you wanted to keep the other version, just add before the <code>exit 0</code> line:<br> <code>cp -f $3 $2</code>.<br> That's it. You merge driver would aways keep the version coming from the other branch, overriding any local change)</p> <p>Now, let's retry the merge from the beginning:</p> <pre><code>git reset --hard HEAD is now at ec202aa prepare myBranch with .gitattributes merge strategy git merge hisBranch Auto-merging dirWithConflicts/a.txt CONFLICT (content): Merge conflict in dirWithConflicts/a.txt Auto-merging dirWithCopyMerge/b.txt Automatic merge failed; fix conflicts and then commit the result. </code></pre> <p>The merge fails... <strong>only for a.txt</strong>.<br> Edit a.txt and leave the line from 'hisBranch', then:</p> <pre><code>git add -A git commit -m "resolve a.txt by accepting hisBranch version" [myBranch 77bc81f] resolve a.txt by accepting hisBranch version </code></pre> <p>Let's check that b.txt has been preserved during this merge</p> <pre><code>type dirWithCopyMerge\b.txt b myLineForB </code></pre> <p>The last commit does represent the <em>full</em> merge:</p> <pre><code>git show -v 77bc81f5e commit 77bc81f5ed585f90fc1ca5e2e1ddef24a6913a1d Merge: ec202aa 658c31c git merge hisBranch Already up-to-date. </code></pre> <p>(The line beginning with Merge does prove that)</p> <hr> <p>Consider you can define, combine and/or overwrite merge driver, as Git will:</p> <ul> <li>examine <code>&lt;dir&gt;/.gitattributes</code> (which is in the same directory as the path in question): will prevail upon the other <code>.gitattributes</code> in directories</li> <li>Then it examines <code>.gitattributes</code> (which is in the parent directory), will only set directives if not already set</li> <li>Finally it examines <code>$GIT_DIR/info/attributes</code>. This file is used to override the in-tree settings. It will overwrite <code>&lt;dir&gt;/.gitattributes</code> directives.</li> </ul> <p>By "combining", I mean "aggregate" multiple merge driver.<br> <a href="https://stackoverflow.com/users/639033/nickgreen">Nick Green</a> tries, <a href="https://stackoverflow.com/questions/928646/how-do-i-tell-git-to-always-select-my-local-version-for-conflicted-merges-on-a-s#comment54034973_930495">in the comments</a>, to actually combine merge drivers: see "<a href="https://gist.github.com/nickgr6/a6837b0c01a4f230bc26" rel="nofollow noreferrer">Merge pom's via python git driver</a>".<br> However, as mentioned in <a href="https://stackoverflow.com/q/33412003/6309">his other question</a>, it only works in case of conflicts (concurrent modification in both branches).</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload