追加と削除の回数を追跡したい。入らないようにする行が移動されました。したがって、コミットに追加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として指定したいと思います。各コミットによって移動された行は、各コミットのループで次のようにして見つけることができます。
- Grep は + または - で始まる行を変更します。
- ストリップ先行+または-
sort
uniq -d
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
。プログラムはそれを解析し、SHAを使用して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
。たとえば、行がabc
5回追加され、3回削除されたとします。(min 3 5)
はい3
、移動された行数ですabc
。今回の出退勤。 3回削除しabc
て5回追加すると、3回移動を意味します。これは決して動きを検出する完全なアルゴリズムではありません。線を検出できないなど、明らかな欠陥があります。実は移動しますが、インデントなどの小さな空間の変化も経験します。