Is there a way to compare two diffs or patches?

混江龙づ霸主 提交于 2019-12-17 09:40:50

问题


Is there a way to test if two diffs or patches are equivalent?

Let's say you have the following git commit history, where features F and G are cleanly rebaseable to E:

     G
    /
A--B--C--D--E
 \
  F

Due to limitations in our current deployment process, we have the following, somewhat related graph (it's not version controlled)

              G'
             /
------------E'
             \
              F'

F' and G' will ultimately be applied to the head E', in some to be determined order, so it would end up like

------------E'--G'--F'

Is there a way to test that the diff from E' to G' is the same as the patch produced by the git commit of G from B?

I fully realize that in an ideal world, revision control would solve this, and we're getting there, but that's not where we are currently.

You could essentially play both patches on separate checkouts and compare the outputs, but that seems kind of clunky. And comparing the diffs themselves, I'm assuming, wouldn't work because line numbers could change. Even if G' and F' were rebased to E', the patch for F' would ultimately be applied to G', making the diff context of the patch different.


回答1:


diff <(git show COMMIT1SHA) <(git show COMMIT2SHA)



回答2:


Since git 2.19 there is an extra tool for that: git range-diff

So you probably want:

git range-diff E..G E..G'

This should work even for more than one patch in each range.




回答3:


For the benefit of the reader, here is an update to the answer of @mrbrdo with a little tweak:

  • Adds git sdiff alias for easy access of this. sdiff stands for show diff.
  • Ignore annotated tag headers using the ^{} suffix.
  • Allow diff options to be used like -u etc.

Run this once in each of your accounts in which you use git:

git config --global alias.sdiff '!'"bash -c 'O=(); A=(); while x=\"\$1\"; shift; do case \$x in -*) O+=(\"\$x\");; *) A+=(\"\$x^{}\");; esac; done; g(){ git show \"\${A[\$1]}\" && return; echo FAIL \${A[\$1]}; git show \"\${A[\$2]}\"; }; diff \"\${O[@]}\" <(g 0 1) <(g 1 0)' --"

Afterwards you can use this:

git sdiff F G

Please note that this needs bash version 3 or above.

Explained:

  • git config --global alias.sdiff adds an alias named git sdiff into the global ~/.gitconfig.

  • ! runs the alias as shell command

  • bash -c we need bash (or ksh), as <(..) does not work in dash (aka. /bin/sh).

  • O=(); A=(); while x="$1"; shift; do case $x in -*) O+=("$x");; *) A+=("$x^{}");; esac; done; separates options (-something) and arguments (everything else). Options are in array O while arguments are in array A. Note that all arguments get ^{} attached, too, which skipps over annotations (such that you can use annotated tags).

  • g(){ git show "${A[$1]}" && return; echo FAIL ${A[$1]}; git show "${A[$2]}"; }; creates a helper function, which does git show for the first argument. If that fails, it outputs "FAIL first-argument" and then outputs the second argument. This is a trick to reduce the overhead in case something fails. (A proper error managment would be too much.)

  • diff "${O[@]}" <(g 0 1) <(g 1 0) runs diff with the given options against the first argument and the second argument (with said FAIL-error fallback to the other argument to reduce the diff).

  • -- allows to pass diff-options (-something) to this alias/script.

Bugs:

  • Number of arguments is not checked. Everything behind the 2nd argument is ignored, and if you give it too few, you just see FAIL or nothing at all.

  • Errors act a bit strange and clutter the output. If you do not like this, run it with 2>/dev/null (or change the script appropriately).

  • It does not return an error if something breaks.

  • You probably want to feed this into a pager by default.

Please note that it is easy to define some more aliases like:

git config --global alias.udiff '!git sdiff -u'
git config --global alias.bdiff '!git sdiff -b'

git config --global alias.pager '!pager() { cd "$GIT_PREFIX" && git -c color.status=always -c color.ui=always "$@" 2>&1 | less -XFR; }; pager'
git config --global alias.ddiff '!git pager udiff'

I hope this does not need to be explained further.

For more aliases like that, perhaps have a look at my GitHub repo




回答4:


I would just let git try and see:

git checkout E -b FG
git cherry-pick F' G'
git checkout E -b GF
git cherry-pick G' F'
git diff FG GF
git branch -D FG GF


来源:https://stackoverflow.com/questions/8569699/is-there-a-way-to-compare-two-diffs-or-patches

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!