gitは行の移動を報告します。

gitは行の移動を報告します。

追加と削除の回数を追跡したい。入らないようにする行が移動されました。したがって、コミットに追加10個、削除5個、移動された行3個がある場合は追加7個、削除2個があります(移動された行は計算しません)。 10と5は次のコードで提供されます。 3つを作成する必要があります(弱く移動された行の巻き取りが必要です(たとえば、同じコミットである場所から同時に削除され、別の場所に追加される行など)。

gitリポジトリで重要なファイルの追加と削除の数を追跡するために、次のコマンドを使用しています。

git log --since=2014-08-01 --date=short --pretty=format:"%ad%x09" --numstat -- file.tex

これにより、次のような結果が生成されます。ここで、最初の数字は追加で、2番目の数字は削除です。

2014-08-19      
72      0       file.tex

2014-08-19      
211     290     file.tex

...

3番目の列を追加し、名前をMove Rowとして指定したいと思います。各コミットによって移動された行は、各コミットのループで次のようにして見つけることができます。

  1. Grep は + または - で始まる行を変更します。
  2. ストリップ先行+または-
  3. sort
  4. uniq -d
  5. wc -l

この疑似コードを実行するための迅速でエレガントな方法はありますか?それとも、必要なものを得るために完全なgit diffをダンプして解析する必要がありますか?

ベストアンサー1

私は次の実装を書いた。TxR言語。まず、アルゴリズムを使用して移動数を決定します。しかし、役に立たない結果が出たことがわかりました。たとえば、単純に一部の行が重複している+ため、行のみを含む変更で「行移動」の正の値を識別しました。+新しいアルゴリズムは最後のコメントで議論されます。

フルプログラム:

#!/usr/bin/env txr
@(bind option-spec
       @(list (opt nil "since" :str
                   "Specifies the starting date (passed \
                   \ through to git); it is mandatory.")
              (opt nil "help" :bool
                   "Prints this help text")))
@(bind parsed-opts @(getopts option-spec *args*))
@(if (or [parsed-opts "help"] (not [parsed-opts "since"])))
@  (output)

usage: @{self-path} --since=<date> -- git arguments
@  (end)
@  (do (opthelp option-spec)
       (exit 0))
@(end)
@(do
   (defun histogram (strings)
     [group-reduce (hash :equal-based) identity (op succ @1) strings 0])

   (defun moved (a b)
     (let* ((hist-a (histogram a))
            (hist-b (histogram b))
            (isec [hash-isec hist-a hist-b min]))
       [reduce-left + (hash-values isec) 0])))
@(next (open-command `git log --since=@[parsed-opts "since"] \
                     \ --date=short --pretty=format:"%H:%ad%x09" \
                     \ --numstat @{parsed-opts.out-args}`))
@(repeat)
@sha:@date@\t
@  (collect :gap 0)
@added@\t@removed@\t@rawpath
@    (next :string rawpath)
@    (cases)
@pro/{@before => @after}/@epi
@      (bind path `@pro/@after/@epi`)
@    (or)
@before => @after
@      (bind path after)
@    (or)
@      (bind path rawpath)
@    (end)
@    (next (open-command `git show -p @sha -- @path`))
@    (collect :vars ((+line nil) (-line nil)))
@      (cases)
+@{+line}
@      (or)
-@{-line}
@      (end)
@    (end)
@    (flatten -line +line)
@    (bind moved @(moved +line -line))
@  (end)
@  (output)
@date@\t
@    (repeat)
@added@\t@removed@\t@moved@\t@rawpath
@    (end)

@  (end)
@(end)

タグ付きの実行ファイルに入れました。movedlines.txr使用法の例は次のとおりです。

$ ./movedlines.txr --since=2017-01-01 path/to

この--sinceオプションは必須です。path/toに渡されるオプションのパラメータですgit。 force オプションを指定しないか指定すると、--helpプログラムはヘルプ・サマリーを印刷して終了します。

メモ:

  • git日付の左側にコロンで区切られたSHAを含むように、サンプルコマンドの出力形式を少し変更しました%H。プログラムはそれを解析し、S​​HAを使用してgit show -p各コレクション内の各ファイルに対して操作を実行できます。プログラムが移動した列を追加してシミュレーション出力を逆流する場合、SHAは省略されます。

  • gitの出力は、名前の変更が複雑な問題であることを示しています。文法は3つのケースに分かれており、@(cases)この構文を使用すると明確で簡単に解析できます。フルパスの名前を変更すると、に名前を変更しますfrom => to。一部のコンポーネントの名前だけを変更した場合be/fore/{from => to}/after。複数の中かっこ構文がパスに表示されるかどうかわかりません。 gitが理解していないので、この構文を変更して通常のパスに変換する必要があります。つまり、be/fore/{from => to}/afterに変換する必要がありますbe/fore/to/after。シンボルなしでパスをこの方法で出力できるgitオプションがあるかもしれません。

  • が使用されるため、パラメータリストがopen-command必要です。open-process

  • アルゴリズムは、diff-+line(先行-OR減算+)の個々の頻度ヒストグラムを計算します。次に、両方のヒストグラムに表示されるヒストグラム項目のみを保持するこれらのセットの交差集合を計算します。交差点の結合機能はですmin。たとえば、行がabc5回追加され、3回削除されたとします。(min 3 5)はい3、移動された行数ですabc。今回の出退勤。 3回削除しabcて5回追加すると、3回移動を意味します。これは決して動きを検出する完全なアルゴリズムではありません。線を検出できないなど、明らかな欠陥があります。実は移動しますが、インデントなどの小さな空間の変化も経験します。

おすすめ記事