Gitで指定した行だけを別ファイルへ移動し、Git管理する方法
背景
Gitで管理しているファイルを整理していると、一部の行だけを別ファイルへ切り出したくなることがある。
単純にコピーするだけなら難しくないが、今回は次の条件を満たしたかった。
- 指定した行だけを別ファイルへ保存する
- 元ファイルからはその行を削除する
- 切り出したファイルもGitで履歴管理する
調べてみると、head・tail・sed を組み合わせることでシンプルに実現できた。
問題
最初はファイルの先頭40行を別ファイルへ保存したかった。
途中で要件が変わり、最終的には「4〜2898行目を別ファイルへ移動する」ことになった。
また、git diff | head -40 のようなコマンドと混同しやすい点にも注意が必要だった。
-
head -40 source_fileはファイル本体の先頭40行を取得する -
git diff | head -40は差分表示の先頭40行を取得する
似ているようで用途はまったく異なる。
先頭40行を別ファイルへ保存する
先頭40行だけを保存する場合は head を使う。
head -40 source_file > extracted_lines
この時点では元ファイルは変更されない。
元ファイルから先頭40行を削除する
保存したあと、元ファイルから削除する場合は tail を利用する。
src="source_file"
dst="extracted_lines"
head -40 "$src" > "$dst"
tail -n +41 "$src" > "$src.tmp" &&
mv "$src.tmp" "$src"
tail -n +41 は41行目以降を出力する。
一時ファイルを経由しているため、途中で失敗した場合でも元ファイルが壊れにくい。
指定した行を別ファイルへ移動する
今回最終的に必要だったのは、4〜2898行目を別ファイルへ移動することだった。
sed を使うとシンプルに書ける。
src="source_file"
dst="extracted_lines"
# 4〜2898行目を保存
sed -n '4,2898p' "$src" > "$dst"
# 元ファイルから4〜2898行目を削除
sed '4,2898d' "$src" > "$src.tmp" &&
mv "$src.tmp" "$src"
使用しているコマンドは次のとおり。
| コマンド | 内容 |
|---|---|
sed -n '4,2898p' |
4〜2898行目だけを出力 |
sed '4,2898d' |
4〜2898行目を削除した結果を出力 |
直接元ファイルを書き換えるのではなく、一時ファイルへ出力してから置き換えている。
Gitで履歴管理する
切り出したファイルもGitで管理する場合は、元ファイルと新しいファイルを両方追加する。
まずは差分を確認する。
git diff -- "$src" "$dst"
git status --short
問題なければコミットする。
git add "$src" "$dst"
git commit -m "Move lines 4-2898 into a separate file"
これで次の変更履歴をGitで追跡できる。
- 元ファイルから指定行が削除された履歴
- 新しいファイルが追加された履歴
PowerShellで行う場合
Windows環境ではPowerShellでも同様のことができる。
$src = "source_file"
$dst = "extracted_lines"
$lines = Get-Content $src
# 4〜2898行目を保存
$lines[3..2897] | Set-Content $dst
# 元ファイルから4〜2898行目を削除
$lines[0..2] + $lines[2898..($lines.Count - 1)] |
Set-Content $src
PowerShellでは配列の添字が0から始まるため、
- 4行目 → インデックス3
- 2898行目 → インデックス2897
となる点に注意したい。
また、ファイルが2898行未満の場合はエラーになるため、必要に応じて事前に行数を確認すると安全である。
(Get-Content $src).Count
学んだこと
今回の調査で整理できた点は次のとおり。
-
headはファイルの先頭行を取得する。 -
tail -n +Nは指定行以降を取得できる。 -
sed -n '開始,終了p'で指定範囲だけを抽出できる。 -
sed '開始,終了d'で指定範囲を削除できる。 - 元ファイルは一時ファイル経由で更新したほうが安全。
- 切り出したファイルも
git addすれば通常どおり履歴管理できる。 -
git diff | head -40は差分表示の先頭40行であり、ファイルの先頭40行ではない。
まとめ
Git管理中のファイルから一部の行を別ファイルへ分離する場合は、head・tail・sed を組み合わせるだけで実現できる。
特に指定範囲の抽出と削除は sed を使うと簡潔で分かりやすい。
最後に元ファイルと新しいファイルを両方 git add すれば、変更履歴もGitで継続して管理できる。