ディスカッション (11件)
新しいプロジェクトのコードや、他人の書いたソースコードをいきなり読み始めていませんか?実は、コードを一行ずつ追う前にGitコマンドで開発の経緯や文脈を把握するだけで、理解のスピードが劇的に変わります。この記事では、コード解読の「下準備」として実行すべきGitコマンドについて紹介されています。履歴を掘り下げ、プロジェクトの全体像を掴むための必須テクニックをチェックしましょう。
誰か興味があるかもしれないので、Jujutsu(jj)での同等のコマンドを置いておくね。
一番変更されているファイル
jj log --no-graph -r 'ancestors(trunk()) & committer_date(after:"1 year ago")' \
-T 'self.diff().files().map(|f| f.path() ++ "\n").join("")' \
| sort | uniq -c | sort -nr | head -20
誰がこれを作ったか
jj log --no-graph -r 'ancestors(trunk()) & ~merges()' \
-T 'self.author().name() ++ "\n"' \
| sort | uniq -c | sort -nr
バグはどこに集まっているか
jj log --no-graph -r 'ancestors(trunk()) & description(regex:"(?i)fix|bug|broken")' \
-T 'self.diff().files().map(|f| f.path() ++ "\n").join("")' \
| sort | uniq -c | sort -nr | head -20
プロジェクトは加速しているか、停滞しているか
jj log --no-graph -r 'ancestors(trunk())' \
-T 'self.committer().timestamp().format("%Y-%m") ++ "\n"' \
| sort | uniq -c
チームはどれくらい火消しに追われているか
jj log --no-graph \
-r 'ancestors(trunk()) & committer_date(after:"1 year ago") & description(regex:"(?i)revert|hotfix|emergency|rollback")'
シェルスクリプトというよりはプログラミングに近い感じで、かなり冗長だけど、覚えるフラグは少なくて済むよ。
過去1年で最も変更されたファイルトップ20。リストのトップにあるファイルは、大抵の場合、誰かに忠告されたファイルだ。「ああ、あのファイルね。みんな触るのを怖がってるよ」
一番変更されているファイルが、みんなが触るのを怖がっているファイルだってこと?
いくつかいいアイデアだけど、正規表現には単語境界を入れたほうがいいね。例えばこんな感じ。
git log -i -E --grep="\b(fix|fixed|fixes|bug|broken)\b" --name-only --format='' | sort | uniq -c | sort -nr | head -20
「debugger」っていう名前の大きなパッケージがあるプロジェクトを抱えてるんだけど、「debugger」の中に「bug」が含まれてるせいで、元のコマンドだとめちゃくちゃになっちゃうんだ。
自分も似たようなことをするsummaryエイリアスを使ってるよ。
# summary: よく使う指標の便利な要約を表示
summary = "!f() { \
printf \"このブランチのサマリー...\n\"; \
printf \"%s\n\" $(git rev-parse --abbrev-ref HEAD); \
printf \"%s 最初のコミット日時\n\" $(git log --date-order --format=%cI | tail -1); \
printf \"%s 最新のコミット日時\n\" $(git log -1 --date-order --format=%cI); \
printf \"%d コミット数\n\" $(git rev-list --count HEAD); \
printf \"%d 日数\n\" $(git log --format=oneline --format=\"%ad\" --date=format:\"%Y-%m-%d\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
printf \"%d タグ数\n\" $(git tag | wc -l); \
printf \"%d 作成者数\n\" $(git log --format=oneline --format=\"%aE\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
printf \"%d コミッター数\n\" $(git log --format=oneline --format=\"%cE\" | awk '{a[$0]=1}END{for(i in a){n++;} print n}'); \
printf \"%d ローカルブランチ数\n\" $(git branch | grep -v \" -> \" | wc -l); \
printf \"%d リモートブランチ数\n\" $(git branch -r | grep -v \" -> \" | wc -l); \
printf \"\nディレクトリのサマリー...\n\"; \
printf \"%s\n\" $(pwd); \
printf \"%d git ls-filesによるファイル数\n\" $(git ls-files | wc -l); \
printf \"%d findコマンドによるファイル数\n\" $(find . | wc -l); \
printf \"%d ディスク使用量\n\" $(du -s | awk '{print $1}'); \
printf \"\n最もアクティブな作成者(コミット数と%%)...\n\"; git log-of-count-and-email | head -7; \
printf \"\n最もアクティブな日付(コミット数と%%)...\n\"; git log-of-count-and-day | head -7; \
printf \"\n最もアクティブなファイル(チャーン数)\n\"; git churn | head -7; \
}; f"
追記: https://github.com/GitAlias/gitalias に感謝。
各コマンドが何をしていて、何がわかるのかを説明するためにLLMを使ってふわっとした段落を書かせるよりも、実際の出力結果(必要なら省略して)を見せたほうがよかったんじゃないかな。
注意点:スカッシュマージのワークフローでは作者情報が圧縮されてしまう。もしチームが全てのPRを1つのコミットにスカッシュしているなら、この出力結果は『誰が書いたか』ではなく『誰がマージしたか』を反映している。結論を出す前にマージ戦略について確認するのが賢明だよ。
自分の経験から言うと、スカッシュしていない場合、これはチームの中で一番散らかしているメンバーを映し出すことになる。
自分が管理しているリポジトリで一番コミット数が多い人は、2番目の人より8倍も多いんだけど、私が参加する前に解雇されてて、何をしてたのか誰も覚えてないんだ。Gitの記録を見ると、大したことはしてなくて、同じ数ファイルを何度も何度もいじってただけだった。
もちろん、誰も自分のコミットで散らかしていないなら問題ないけど、そうじゃないならスカッシュした方が実際を正確に反映していることもあるよね。
著者が『開発者はちゃんとコミットメッセージを書く』と思ってるのが面白いね。
冗談はさておき、これは企業の世界で慢性的な問題なんだ。私が出会ったコードベースのほとんどは「何かを変えた」とか「これで動くといいな」みたいなものばかりだよ。
gitのコミットログは時間をかけて意味のあることを書く価値があると考えている開発者は、ごく少数派(私も含めてね)。
AIによるコミットメッセージ生成は、もし開発者が実際にそれを使ってくれれば(使ってくれるといいんだけど)、かなり助けになるはず。
「コミット数」なんてあてにしないほうがいいよ。「コミット」の中身や質は開発者によって全然違うからね。私のチームには、ローカルで徹底的にテストした動作するコードしかコミットしない人がいる一方で、動かない1行だけの変更をコミットして、その後に修正、また修正と繰り返す人もいる。後者の「コミット」は、前者の1/100くらいの価値しかないんだ。
いくつかのコードベースでこれらのコマンドを試してみたけど、私が知っている現実とは全く違う状況を描き出していると言わざるを得ないね。
git shortlog -sn --no-merges
これが一番ひどい。あるコードベースでは、2位の人の3倍近いコミット数を叩き出している開発者がトップにいたんだけど、その人はもう会社にいないんだ。危機的状況か?いや、逆だよ。その開発者はチームにとって様々な意味でマイナスの存在で、コードベースを全く理解していなかったのに、なぜか何かあるたびにコミットを連発していただけだった。
この考え方はいいね。Adam Tornhillの『Your code as a crime scene』を思い出したよ。
https://www.adamtornhill.com/articles/crimescene/codeascrime...
あと、関連性は薄いけど、「Developer's Legacy Index(開発者の遺産インデックス)」という考え方も面白いね。
https://www.javaadvent.com/2021/12/using-jgit-to-analyse-the...