🐊

あなたは知ってる?ちょっとマイナーな Git の小ネタ

2023/10/30に公開

未コミットのファイルを diff に含める / add -N / add --intent-to-add

https://git-scm.com/docs/git-add/ja#git-add---intent-to-add
通常 untracked file は diff で差分を表示できないが、git add -N することで diff で差分を確認できるようになる
commit 前に diff を使って差分を確認しつつ確認できたものを add していくときによく使う

仕組みとしては単純で、add -N / --intent-no-add で指定したファイルを空のファイルとして add しているので差分が表示できるようになっている
https://stackoverflow.com/questions/24329051/what-does-git-add-intent-to-add-or-n-do-and-when-should-it-be-used/24347875#24347875

ファイルを細かい単位で add する / add -p / add --patch

https://git-scm.com/docs/git-add/ja#git-add--p
一度に大量のコードを書いてしまったあとに、機能ごとにコミットの粒度を細かくしたい場合などに使える
[y, n, q, a, d, g, /, i, J, k, K, s ,e ?] の選択肢があるがだいたい使うのは [y, n, q, a, s, e]

以下は add -p 使用時の一例

  1. 一気に実装する
  2. git add -p {file} で patch モードへ
  3. コミットしたい単位で y / n を入力して staging していく
    1. 提案された単位より小さい単位で staging したい場合は s で小さくする
    2. s が使えなかったり上手くいかない場合は e で手動選択

プロジェクトによっては粒度を気にせず git rebase してまとめたりするので使わないこともある

CLI で扱いやすい status 表示 / status --porcelain

https://git-scm.com/docs/git-status#Documentation/git-status.txt---porcelainltversiongt
git status で表示される情報を cli などで処理しやすいで出力してくれる
基本的には git status -s / --short と結果が変わらないが、 --porcelain はバージョン指定ができる(デフォルトは v1)ので、ユーザの環境や git のバージョンに依存せず同じ結果を返せることが特徴
この特徴のおかげで過去に作ったスクリプトが git のバージョンアップ後に動かなくなる問題を防げる

筆者は sed を噛ませつつ goimports に渡したりするのに良く使っている
git status --porcelain | sed s/^...// | xargs goimports -w

行単位ではなく単語単位で diff 表示 / diff --word-diff

https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---word-diffltmodegt

通常行単位で比較する diff を単語単位で比較して出力してくれる
表示オプションとして [color, plain, porcelain] があるが個人的には color か porcelain が使いやすいと思う
メール文面やユーザ向けのお知らせなど、単語単位で diff を取ってチェックしたいときに便利(GitHub の PR Diff が word-diff 対応してくれると嬉しい)

ちなみに

https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---color-wordsltregexgt
--color-words のオプションもあるが、これは --word-diff=color と同じ出力になる
git diff --no-index --color-words a.txt b.txt

git 管理外のファイルでも diff 表示 / diff --no-index

https://git-scm.com/docs/git-diff#Documentation/git-diff.txt-codegitdiff--no-indexabcode
git 管理をしていないけど git diff で差分を取りたい場合は --no-index オプションを使って比較する
git diff --no-index --word-diff=color a.txt b.txt

untracked ファイルを stash する / stash -u / stash --include-untracked

https://git-scm.com/docs/git-stash#Documentation/git-stash.txt--u
untracked なファイルもまとめて stash するときに使う
untracked を含めたくない場合は --no-include-untracked を使う
逆の --only-untrackedstash show 専用なため untracked のみを stash はできない。git add -N と組み合わせたりして解決する

ちなみに

https://git-scm.com/docs/git-stash#Documentation/git-stash.txt-save-p--patch-S--staged-k--no-keep-index-u--include-untracked-a--all-q--quietltmessagegt
stash する際には stash に名前をつけると思うが、順番に気をつけないと構文エラーになる
OK: git stash save "hoge" -u
NG: git stash -u save "hoge"

指定したコミットで変更したファイル名のみ取得 / show --pretty="" --name-only

https://git-scm.com/docs/git-show#Documentation/git-show.txt---name-only

push 後にフォーマット漏れで CI の Linter に怒られたりした場合に時々使う
フォーマットとは別に修正も入れたいし、かと言って修正とフォーマットを同一コミットにしたくないときに使える
通常 git show {hash} は指定したコミットハッシュの変更内容を表示するが、--name-only のオプションで変更内容ではなく変更されたファイルの情報のみ取り出せる

$ git show --name-only 12345abc
commit 12345abc
Author: i_love_wani <example@example.com>
Date:   Sat Jan 01 00:00:00 2000 +0900

    hoge/piyo を修正

hoge/fuga/main.go
hoge/piyo/main.go

ただ、この状態だとフォーマッター(例えば gofmt)にわたすには Author などの情報が邪魔なので --pretty="" で削る

$ git show --name-only --pretty="" 12345abc
hoge/fuga/main.go
hoge/piyo/main.go

するとファイル名のみを取り出すことができるので、後は xargs などを使ってフォーマッターにパスを渡す
git show --name-only --pretty="" 12345abc | xargs gofmt -w

任意のディレクトリに対して git コマンドを実行 / git -C {path}

https://git-scm.com/docs/git#Documentation/git.txt--Cltpathgt
{path} で指定したディレクトリで git コマンドを実行できる
複数のリポジトリに対してまとめて git 操作したい場合に便利(cd が不要)

例: 指定したディレクトリ配下のリポジトリに対して git pull --rebase を実行するスクリプト

※ fish script です

function pullall
  set branchName 'develop'
  if test (count $argv) -gt 0
    set branchName $argv
  end
  cd ~/hoge/ && find . -type d -depth 1 -exec git -C {} switch $branchName \; -exec git -C {} pull --rebase \;
end

$ pullall feature/hoge` という感じで使えます
やっていることは

  1. hoge ディレクトリに移動
  2. hoge ディレクトリ配下を find し、以下の処理を配下のディレクトリに対して実行
  3. git -C {} switch $branchName で指定したブランチをチェックアウト(引数がない場合は develop になる)
  4. git -C {} pull --rebasepull --rebase する

変更を維持したまま stash に保存する / stash -k / stash --keep-index

https://git-scm.com/docs/git-stash#Documentation/git-stash.txt--k
現在 index に追加している差分のみ stash できる
save か push(git stash と同等)のみ使える

コミットしたくないけど逃しておきたい変更(一時的に DB の接続先を変えるとか)がある場合に使える
e.g.

  1. .env ファイルを修正して DB の接続先を変更
  2. この修正は今後も時々使ったりする
  3. git add .env で index に追加
  4. git stash save "tmp db connection" -k
  5. 現在の index の状態はそのままに .env の変更が stash に保存される

最小限の差分で表示する / diff --minimal

https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---minimal
大量の行を一度に削除した場合(1000行削除したとする)などに +1000 -1000 といったように行が移動したような差分として表示された場合に使える
時間はかかるが正確な diff を取るアルゴリズムを使うので -1000 という正しい差分を表示できる

おまけ: Conversion を全部 resolve する

CI でめちゃめちゃ怒られたけど、全部無視したいときに使ってみてください

javascript:(function(){document.querySelectorAll('.ajax-pagination-btn').forEach((b)=>{b.click()}); setTimeout(function(){document.querySelectorAll('[data-disable-with="Resolving conversation…"]').forEach((b)=>{b.click()});}, 5000);})();

ブックマークレットとして使えます

EGSTOCK,Inc.

Discussion