tar 実践 - 増分バックアップと除外・展開先指定
tar の増分バックアップとは?
結論: 前回からの変更分だけをアーカイブする方式。
--listed-incrementalでスナップショットを記録し、差分を判定する。
tar の基本で圧縮・解凍ができるようになったら、次は実務で必須の3点を押さえる。
- 増分(差分)バックアップ: 毎回フルコピーせず、変更分だけ取る
- 除外:
node_modulesやキャッシュなど不要なものを外す - 展開先・パス制御: どこに、どの階層で展開するかを固定する
この記事の前提
- OS: Ubuntu(GNU tar)
tar --versionでGNU tarと表示されること(増分・除外オプションは GNU tar 固有)- BSD tar(macOS 標準)では一部オプションが異なる
なぜ --listed-incremental を使うのか?
結論:
--listed-incrementalは削除・移動も追跡できる。--newer(mtime 比較)は削除を検知できず復元時に取りこぼす。
増分バックアップには2つの方式がある。
| 方式 | 判定基準 | 削除の追跡 | 推奨 |
|---|---|---|---|
--listed-incremental (-g) |
スナップショット記録 | できる | ◎ |
--newer / --after-date |
mtime(更新時刻) | できない | △ |
--newer は「指定時刻より新しいファイル」を拾うだけなので、前回以降に削除されたファイルを記録できない。復元すると消したはずのファイルが復活する。--listed-incremental はディレクトリ状態をスナップショットファイル(慣習的に .snar 拡張子)に記録するため、削除も含めて正しく差分を再現できる。
mtime ベースの --newer は「とりあえず差分」には使えるが、世代管理・正確な復元を要する用途では --listed-incremental を使う。
増分バックアップの作り方
結論: 同じスナップショットファイルを
-gで指定し続ける。初回は自動でレベル0(フル)、2回目以降はレベル1以降(差分)になる。
レベル0(フルバックアップ)
スナップショットファイルが存在しない初回は、自動的にフルバックアップになる。
$ tar -czg /backup/home.snar -f /backup/home-full.tar.gz /home/user/
-g /backup/home.snar: スナップショット(--listed-incrementalの短縮形)-c: 作成 /-z: gzip /-f: 出力ファイル- 実行後、
home.snarにディレクトリ状態が記録される
レベル1以降(増分)
同じスナップショットファイルを指定して再実行すると、前回からの変更分だけがアーカイブされる。
$ tar -czg /backup/home.snar -f /backup/home-inc1.tar.gz /home/user/
home.snar は実行のたびに更新され、次回の差分判定に使われる。アーカイブ名(home-inc1, home-inc2...)は世代ごとに変える。
毎回フルを取りたい場合
-g /dev/null を指定すると、スナップショットが保存されない(/dev/null は書き込んでも残らない)ため、常にレベル0フルバックアップになる。
$ tar -czg /dev/null -f /backup/full.tar.gz /home/user/
スナップショットファイルはバックアップ本体とは別に保全する。.snar を失うと差分の連鎖が切れ、次回が意図せずフル相当になったり復元手順が崩れたりする。
増分バックアップからどう復元するのか?
結論: レベル0から順に、世代順で展開する。展開時も
--listed-incrementalを付けると削除も再現される。
復元は作成した順番どおりに展開するのが鉄則。
$ mkdir -p /restore $ tar -xzg /dev/null -f /backup/home-full.tar.gz -C /restore $ tar -xzg /dev/null -f /backup/home-inc1.tar.gz -C /restore $ tar -xzg /dev/null -f /backup/home-inc2.tar.gz -C /restore
- 展開時の
-gには/dev/nullを渡す(スナップショットの中身は復元時には参照されないが、--listed-incrementalモードを有効にするために指定する) - このモードでは、増分で削除されたファイルは展開先からも削除される(正しい世代再現)
展開時に -g(--listed-incremental)を付け忘れると、削除の再現が行われず、古い世代で消したファイルが残ったままになる。世代を正確に再現したい場合は必ず付ける。
中身を先に確認したいとき
展開前に各アーカイブの中身を一覧で確認する。
$ tar -tzf /backup/home-inc1.tar.gz | head
増分アーカイブには、変更されたファイルに加えてディレクトリのエントリも含まれる。
除外パターンの指定方法
結論:
--exclude=PATTERNで個別除外、--exclude-from=FILEで一覧指定。オプションはソースパスより前に置く。
個別に除外する
$ tar --exclude='*.log' --exclude='node_modules' \
-czf project.tar.gz project/- パターンは glob(
*?[...])で、アーカイブ内のメンバー名に対して照合される --excludeはソースパス(project/)より前に置く(後ろに置くと効かない場合がある)
除外リストをファイルにまとめる
除外対象が多いときは1行1パターンのファイルにする。
$ cat > exclude.txt <<'EOF' *.log *.tmp node_modules .cache EOF $ tar --exclude-from=exclude.txt -czf project.tar.gz project/
--exclude-from の短縮形は -X。
よく使う専用オプション
| オプション | 除外対象 |
|---|---|
--exclude-vcs |
.git / .svn / CVS などのバージョン管理情報 |
--exclude-caches |
CACHEDIR.TAG を含むキャッシュディレクトリ |
$ tar --exclude-vcs --exclude='*.log' -czf src.tar.gz src/
展開先とパス階層をどう制御するのか?
結論:
-Cで展開先ディレクトリを固定、--strip-components=Nで先頭階層を除去、--one-top-levelで1つの親に閉じ込める。
展開先を固定する(-C)
$ tar -xzf project.tar.gz -C /opt/app
カレントディレクトリに散らばる事故を防ぐ基本。展開先は事前に作っておく。
先頭の階層を除去する(--strip-components)
アーカイブが project-1.0/src/... のように1階層深い場合、その階層を剥がして展開できる。
$ tar -xzf project-1.0.tar.gz --strip-components=1 -C /opt/app
project-1.0/ を取り除き、/opt/app/src/... に直接展開される。GitHub のソース tarball を所定の場所へ展開するときの定番。
1つの親ディレクトリに閉じ込める(--one-top-level)
複数のファイルがトップレベルに散らばるアーカイブを、1つのディレクトリ配下に強制的にまとめて展開する。
$ tar -xzf messy.tar.gz --one-top-level=extracted
extracted/ が作られ、その中に展開される(散らかり防止)。
実践:日次バックアップの型
結論: 週次でレベル0、日次でレベル1を回す。除外リストと展開先固定をセットにすれば事故が減る。
コピペ用テンプレ
# 週次フル(スナップショットを初期化したい場合は .snar を消してから)
tar --exclude-from=/etc/backup/exclude.txt \
-czg /backup/home.snar \
-f /backup/home-$(date +%Y%m%d)-full.tar.gz \
/home/user/
# 日次増分(同じ .snar を使い続ける)
tar --exclude-from=/etc/backup/exclude.txt \
-czg /backup/home.snar \
-f /backup/home-$(date +%Y%m%d)-inc.tar.gz \
/home/user/
# 復元(フル → 増分の順、削除も再現)
tar -xzg /dev/null -f /backup/home-...-full.tar.gz -C /restore
tar -xzg /dev/null -f /backup/home-...-inc.tar.gz -C /restoreやってはいけないこと
- 復元を増分から先に展開する(必ずフルが先)
- スナップショット
.snarをアーカイブと同じ場所だけに置く(同時消失リスク) - 展開先を
-Cで固定せず本番ディレクトリで直接展開
定期実行は cron の基本、容量設計はディスクがいっぱいになったときも参照。