web-dev-qa-db-ja.com

git diffの出力をフィルタリングするより良い方法はありますか?

コンテキスト内のSO質問: 変更された行番号をgit diffから見つけます

上記の質問に基づいて、次の形式でgitの2つのリビジョン間の変更されたファイルの差分を出力する必要があります。

_/path/to/file
startline1-startline2
startline3-startline4

/path/to/another/file
startline5-startline6
...
_

これはgit diffの出力をフィルタリングするための私の attempt です。

_git diff --unified=0 --diff-filter=M HEAD~1 HEAD | \
grep -v -e '^[+-]' -e '^index' | \
sed 's/diff --git a.* b\//\//g; s/.*@@\(.*\)@@.*/\1/g; s/^ -//g; s/,[0-9]*//g; s/\(^[0-9]*\) +/\1-/g;'
_

上記のコマンドが_git diff_が出力に表示する可能性のあるすべてのケースを満たしているかどうかはわかりません。

既存のソリューションを改善できますか、またはawkのような他のユーティリティを使用して、またはgit自体でこれを行うより良い方法はありますか?


@ mur によって与えられる answer に基づいて、ここに比較があります:

_# Using git diff [expected output w.r.t line numbers and not formatting]

$ git diff --unified=0 --diff-filter=M HEAD~3 HEAD | grep -v -e '^[+-]' -e '^index'
diff --git a/lib/get-config.js b/lib/get-config.js
@@ -89,0 +90,5 @@ module.exports = {
diff --git a/lib/pull.js b/lib/pull.js
@@ -62 +62 @@ module.exports = class Pull {
@@ -83 +83 @@ module.exports = class Pull {
diff --git a/lib/router.js b/lib/router.js
@@ -3,0 +4 @@ const yaml = require('js-yaml')
@@ -125,0 +127 @@ module.exports = app => {
@@ -136,0 +139 @@ module.exports = app => {
_
_# Using external diff as suggested by @muru
# [expected output with formatting but line numbers don't match with git diff's output]

$ git -c diff.external='./foo.sh' diff --diff-filter=M 'HEAD~3' HEAD
/tmp/AAAA_get-config.js
90-89

/tmp/BBBB_pull.js
62
83

/tmp/CCCC_router.js
4-3
126-125
137-136
_

ファイル_router.js_の行番号は異なります。

リポジトリ 比較に使用されます。


出力で予想される形式を明確にしたいと思います。

_git diff_は、unified diff形式で出力を生成します。形式は次のようなものです。

_# Assumes --unified=0 i.e no context lines
diff --git a/path/to/file b/path/to/file
index x..z mode
--- a/path/to/file
+++ b/path/to/file
@@ -l1,s +l2,s @@ optional section heading
- ...
- ...
+ ...
+ ...
diff --git a/path/to/file1 b/path/to/file1
index y..z mode
--- a/path/to/file1
+++ b/path/to/file2
@@ -l3,s +l4,s @@ optional section heading
- ...
- ...
+ ...
+ ...
.
.
.
_

予想される出力には、(_--diff-filer=M_を使用して)変更されたファイルのみのdiffが含まれ、次の形式である必要があります。

_/path/to/file
l1-l2

/path/to/file1
l3-l4
l5-l6
.
.
.
_

ここで_l1_、_l2_...は、統一されたdiff形式(_@@ -l1,s +l2,s @@_)で述べられている行番号です。


@ muru'sanswer 問題はほぼ解決しますが、この変更されたグループ形式'%df%(f=l?:-%dl)\n'を使用して取得した行番号は、統一されたdiff形式の行番号と一致しません。

_changed-group-format_などのオプションを使用して、行番号を(unified diff形式で)表す方法はありますか?


これが bash git repository を使用したMVCEです。

_git diff_を使用して、

_$ git diff --unified=0 --diff-filter=M 9e49d ad1b3 | grep -v -e '^[+-]' -e '^index'
diff --git a/execute_cmd.c b/execute_cmd.c
@@ -567 +567 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
@@ -753,2 +753 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
@@ -759,2 +758 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
@@ -1104 +1102 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out,
diff --git a/patchlevel.h b/patchlevel.h
@@ -28 +28 @@
diff --git a/subst.c b/subst.c
@@ -5339 +5339 @@ clear_fifo_list ()
@@ -5345 +5345 @@ copy_fifo_list (sizep)
@@ -5411,7 +5411,2 @@ unlink_fifo_list ()
@@ -5433 +5428 @@ close_new_fifos (list, lsize)
@@ -5437 +5431,0 @@ close_new_fifos (list, lsize)
@@ -5445,2 +5439,2 @@ close_new_fifos (list, lsize)
@@ -5568 +5562 @@ clear_fifo_list ()
@@ -5572 +5566 @@ copy_fifo_list (sizep)
@@ -5578 +5572 @@ copy_fifo_list (sizep)
@@ -5583 +5577 @@ copy_fifo_list (sizep)
@@ -5656 +5650 @@ close_new_fifos (list, lsize)
@@ -5660 +5653,0 @@ close_new_fifos (list, lsize)
@@ -5668,2 +5661,2 @@ close_new_fifos (list, lsize)
diff --git a/subst.h b/subst.h
@@ -276,2 +276,3 @@ extern void unlink_fifo __P((int));
_

期待される出力

_/execute_cmd.c
567-567 
753-753 
759-758 
1104-1102 

/patchlevel.h
28-28 

/subst.c
5339-5339 
5345-5345 
5411-5411 
5433-5428 
5437-5431 
5445-5439 
5568-5562 
5572-5566 
5578-5572 
5583-5577 
5656-5650 
5660-5653 
5668-5661 

/subst.h
276-276 
_

@ muru'sanswer に基づく出力

_# Line numbers which don't match the expected output is indicated by "#"
$ git -c diff.external='../foo.sh' diff --diff-filter=M 9e49d ad1b3
/tmp/2wJaWf_execute_cmd.c
567
753-754 #
759-760 #
1104 #

/tmp/7j19Ob_patchlevel.h
28

/tmp/fQDY8b_subst.c
5339
5345
5411-5417 #
5433 #
5437 #
5445-5446 #
.
.
.
_
1

GNU diffを使用し、_git diff_にそれを呼び出させると、同様の結果が得られます。

_foo.sh_

_#! /bin/bash
# See https://stackoverflow.com/a/255212/2072269 for details on parameters
echo "$2" # print filename
diff --changed-group-format $'%df%(f=l?:-%dl)\n' --line-format='' "$2" "$5"
echo
exit 0
_

そして( bash git repo を使用した例):

_$ export GIT_EXTERNAL_DIFF="$PWD/foo.sh"
$ git diff HEAD 'HEAD^^'
execute_cmd.c
567
753-754
759-760
1104

patchlevel.h
28

subst.c
5339
5345
5411-5417
5433
5437
5445-5446
5568
5572
5578
5583
5656
5660
5668-5669

subst.h
276-277
_

GNU diff オプション:

_--changed-group-format=_format
これらの行グループは、両方のファイルからの行を含む塊です。

_%df_および_%dl_は、古いファイル(fecimal内)の変更グループのlirstおよびdast行番号です。 %(f=l?:-%dl)は、flを比較し、最初の行と同じ場合は最後の行を省略した3項式です。

実際の行は必要ないため、_--line-format_は空に設定されています。


MCVEに基づいて、それは思われます:

  1. %(f=l?:-%dl)の3項チェックは必要ありません(最初のチェックと同じ場合、2番目のチェックは省略されます)。 2番目の番号を印刷するだけです。
  2. ほとんどの場合、2番目の数値は_%F_でなければなりません-新しいファイルからの変更の最初の行。古いファイルから行が削除される場所を除いて、新しいファイルの行数は0です。その場合、出力される数は_%E_-新しいファイルのグループの直前の行番号です。次に、3項は%(N=0?%dE:%dF)になります。
  3. ファイル名には、_$1_ではなく_$2_を使用する必要があります。

したがって、これらの変更により:

_#! /bin/bash
# See https://stackoverflow.com/a/255212/2072269 for details on parameters
echo "$1" # print filename
diff --changed-group-format $'%df-%(N=0?%dE:%dF)\n' --line-format='' "$2" "$5"
echo
exit 0
_

期待される出力が得られます:

_$ PAGER=cat git diff --unified=0 --diff-filter=M 9e49d ad1b3
execute_cmd.c
567-567
753-753
759-758
1104-1102

patchlevel.h
28-28

subst.c
5339-5339
5345-5345
5411-5411
5433-5428
5437-5431
5445-5439
5568-5562
5572-5566
5578-5572
5583-5577
5656-5650
5660-5653
5668-5661

subst.h
276-276

_
2
muru