Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>OK, let's tackle a different "reasonably precise" definition based on the question-edit.</p> <p>Given:</p> <ul> <li>merge commit <code>M</code></li> <li>with final tree <code>T</code> containing files <code>f1</code>, <code>f2</code>, ..., <code>fn</code></li> <li>and immediate parents <code>p1</code>, <code>p2</code>, ..., <code>pn</code></li> </ul> <p>you want—regardless of additional possible ancestry<sup>1</sup>—all files <code>f<sub>i</sub></code> where, given any two different parents <code>p<sub>a</sub></code> and <code>p<sub>b</sub></code>, <code>f<sub>i</sub></code> was "modified" in both <code>p<sub>a</sub></code> and <code>p<sub>b</sub></code>.</p> <p>The definition of "modified" here is that for a commit <code>p</code> and file <code>f</code>, <code>p</code> itself has one single parent, <code>p^</code> (so <code>p</code> is neither a merge nor a root commit), and <code>p:f</code> (file <code>f</code> in commit <code>p</code>) differs from <code>p^:f</code> (possibly to the point of not even existing in <code>p^</code>).</p> <p>This suggests the following obvious (and totally un-optimized) algorithm for finding all files <code>f<sub>i</sub></code> in tree <code>T</code> that meet this constraint:</p> <pre><code># set M = merge commit ID and P to its complete list of parents # (see previous scripts for how to achieve that) for f in $(git ls-tree -r $M); do found=false twice=false for p in $P; do $twice &amp;&amp; continue # already announced if modified_in $p $f; then $found &amp;&amp; twice=true || found=true fi $twice &amp;&amp; echo $f # announce if found twice done done </code></pre> <p>where <code>modified_in</code> is defined as:</p> <pre><code>modified_in() { local p=$1 p_hat=$1^ path="$2" assert_single_parent $p # optional: verify neither root commit nor merge # (if you want to do this, it would be more efficient to do it once # outside the "for f in ..." loop) test ! -z "$(git diff-tree -r --diff-filter=AM $p_hat $p -- "$path")" } </code></pre> <p>Here the <code>git diff-tree</code> command will output a line like:</p> <pre><code>:100644 100644 &lt;sha1_in_p^&gt; &lt;sha1_in_p&gt; M c </code></pre> <p>for a file modified between <code>$p_hat</code> and <code>$p</code> (the <em><code>sha1</code></em> values being the blob SHA-1s), and:</p> <pre><code>:000000 100644 &lt;null_sha1&gt; &lt;sha1_in_p&gt; A fgh </code></pre> <p>for a file added there. The <code>--diff-filter=AM</code> ensures no output for a removal (otherwise you would get an <code>R</code> here) and the <code>-- "$path"</code> limits the checking to just the given file-name-path. I am pretty sure (but have not tested) that you need not worry about <code>C</code> and <code>R</code> (copy-edit and rename) and since these are commit tree diffs, not index diffs, <code>U</code> (unmerged) cannot occur. So we just need to run <code>git diff-tree</code> with that filter, and test whether the command prints anything.</p> <p>(To make this [probably much] more efficient, run all possible <code>git diff-tree</code> commands once, without specifying paths, on all "interesting" parents, saving their outputs, then cross-correlate all the files listed. Those that occur twice or more are your candidates. But that's much harder in <code>sh</code> script: you'll need something like <code>awk</code> here.)</p> <p>[Edit: no, you don't need <code>awk</code> after all, <code>sort | uniq -d</code> will do the trick. See <a href="https://stackoverflow.com/a/19139966/1256452">jthill's new answer</a>, which implements the much-more-efficient version of a slightly different interpretation of the question, maybe closer to the real intent, which I admit I still find confusing.]</p> <hr> <p><sup>1</sup>That is, if the commit graph looks something like this, for instance:</p> <pre><code>A -- B -- C -- D -- M -- .. \-- E -- F --/ </code></pre> <p>you only care about changes made in <code>D</code> and <code>F</code> with respect to <code>M</code>, not changes made in <code>C</code> and <code>E</code> as well.</p> <p>If you <em>do</em> care, you may want to diff commit <code>M</code> against, e.g., temporary trees made by squashing together C-and-D, and E-and-F, respectively; or do pairwise comparisons all the way back, or some such. Basically, you will need to list revs between the merge-base (commit <code>B</code>, here) and the merge itself (<code>M</code>), and then figure out how you want to handle them.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

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