もちろん、mkdir ./export && git archive "commit id" "file path" | tar --extract --directory=./export
推奨
↓を使う理由は特にないですw 逆にデメリットがあるかもしれません。
※注意※
現在の "git add
" を取り消して、ステージ経由でファイルを復元します。
また最後に "git add
" を取り消した分をステージに戻します。
その過程で何らかのファイルが削除される可能性があります。
実行環境
・Bash
・Ubuntu Server 22.04
# 0.変数代入
Commit_ID="コミットID(sha1)"
Want_to_restore="抽出したいファイル"
Export_folder="抽出先にしたいディレクトリ"
Work_tree_path="$PWD"
# 1.変数 初期値設定
Commit_ID="${Commit_ID:-HEAD}"
Want_to_restore="${Want_to_restore:-:/}"
Export_folder="${Export_folder:-Export_folder}"
Work_tree_path="${Work_tree_path:-.}"
git_path="`git -C $Work_tree_path rev-parse --absolute-git-dir`"
work_tree_root="`git -C "$Work_tree_path" rev-parse --show-toplevel`"
stage_backup="${work_tree_root%/}/.stage_backup_checkin"
export_path=`cd "$Work_tree_path" && mkdir -p "$Export_folder" && readlink -f "$Export_folder"`
# 2.バックアップ・抽出
git -C "$work_tree_root" checkout-index --force --prefix="${stage_backup%/}/" --all
git -C "$work_tree_root" rm -r --force --ignore-unmatch --quiet --cached -- :/
git -C "$work_tree_root" restore --staged --source="$Commit_ID" -- $Want_to_restore
git -C "$work_tree_root" checkout-index --force --prefix="${export_path%/}/" --all
git -C "$work_tree_root" rm -r --force --ignore-unmatch --quiet --cached -- :/
# 3.ステージにあったファイルを復元
git --git-dir="$git_path" --work-tree="$stage_backup" add .
# 4.ステージ_バックアップの削除
git -C "$work_tree_root" rm -r --force --ignore-unmatch --quiet -- "$stage_backup" \
; rm -rf "$stage_backup"
# 5.抽出したファイルが git の管理除外対象になっていることを確認
# grep --quiet --line-regexp "`basename $export_path`" "$git_path/info/exclude" \
# || echo `basename "$export_path"` >> "$git_path/info/exclude"
# 0.変数代入
Commit_ID="コミットID(sha1)"
Want_to_restore="抽出したいファイル"
Export_folder="抽出先にしたいディレクトリ"
Work_tree_path="$PWD"
# 1.変数 初期値設定
Commit_ID="${Commit_ID:-HEAD}"
Want_to_restore="${Want_to_restore:-:/}"
Export_folder="${Export_folder:-Export_folder}"
Work_tree_path="${Work_tree_path:-.}"
work_tree_root="`git -C "$Work_tree_path" rev-parse --show-toplevel`"
stage_backup="${work_tree_root%/}/.index_backup_tostage"
export_path=`cd "$Work_tree_path" && mkdir -p "$Export_folder" && readlink -f "$Export_folder"`
# 2.バックアップ・抽出
rm -f "$stage_backup"
while read LINE; do
on_stage_A="`cut -f 1 <<< $LINE`"
on_stage_B="`cut -f 2 <<< $LINE`"
echo -e "$on_stage_A"'\t'"\"$on_stage_B\"" >> "$stage_backup"
done < <(git ls-files --stage)
git -C "$work_tree_root" rm -r --force --ignore-unmatch --quiet --cached -- :/
git -C "$work_tree_root" restore --staged --source="$Commit_ID" -- $Want_to_restore
git -C "$work_tree_root" checkout-index --force --prefix="${export_path%/}/" --all
git -C "$work_tree_root" rm -r --force --ignore-unmatch --quiet --cached -- :/
# 3.ステージにあったファイルを復元
git -C "$work_tree_root" update-index --index-info < "$stage_backup"
# 4.ステージ_バックアップの削除
git -C "$work_tree_root" rm --force --ignore-unmatch --quiet -- "$stage_backup" \
; rm -f "$stage_backup"
# 5.抽出したファイルが git の管理除外対象になっていることを確認
# grep --quiet --line-regexp "`basename $export_path`" "$git_path/info/exclude" \
# || echo `basename "$export_path"` >> "$git_path/info/exclude"
詳細
version 1➝2 の変更点
以下のやり方だと blob オブジェクトを新たに追加しない。
git ls-files --stage > "$stage_backup"
mode SP type SP sha1 TAB path
(mode 空白 type 空白 sha1 タブ path)
の形式でインデックスをバックアップ。
git update-index --index-info < "$stage_backup"
バックアップからインデックスに直接記入。
Commit_ID="コミットID(sha1)"
⌇⌇⌇
⌇⌇⌇
export_path="`cd $Work_tree_path && mkdir -p $Export_folder && readlink -f $Export_folder`"
変数に代入、初期値を用意。最後のは、相対パスだった時に絶対パスに変換するもの。
git_path="`git -C $work_tree_root rev-parse --absolute-git-dir`"
$GIT_DIR 及び .git のフルパス("--path-format=absolute --git-dir")を取得する。
work_tree_root="`git -C "$Work_tree_path" rev-parse --show-toplevel`"
--show-toplevel は既定で絶対パスを返す。
git -C "$work_tree_root"
git コマンドを実行する場所を指定。
git checkout-index --force --prefix="${stage_backup%/}/" --all
stage 上のファイルを .stage_backup にコピー。
git rm -r --force --ignore-unmatch --quiet --cached -- `git ls-files`
対象を .git/index から削除し、stage から降ろす( stage を空にする、work_tree からはファイルを削除しない)。
git restore --stage --source="$Commit_ID" -- $Want_to_restore
指定したコミットから、指定したファイルを stage 上に戻す。
git checkout-index --force --prefix="${export_path%/}/" --all
stage 上に戻したファイルを $Export_folder にコピー。
git rm -r --force --ignore-unmatch --quiet --cached -- `git ls-files`
.git/index から削除し、stage を空にする。
git --git-dir="$git_path" --work-tree="$stage_backup" add .
.stage_backup を work_tree に設定し、
ファイルを .stage_backup から stage に上げる。
git rm -r --force --ignore-unmatch --quiet "$stage_backup" \
; rm -rf "$stage_backup"
念のため .git/index から .stage_backup 全体を削除し、work_tree からもファイルとディレクトリを削除する。さらに、git 管理されていない場合の削除も work_tree で実行する。
grep --quiet --line-regexp "`basename $export_path`" "$git_path/info/exclude" \
|| echo "`basename $export_path`" >> "$git_path/info/exclude"
$Export_folder を git 管理対象から除外する。
備考
git -C "$Work_tree_path" checkout-index --force --prefix="${stage_backup%/}/" --all
git -C "$Work_tree_path" rm -r --force --ignore-unmatch --quiet --cached -- `git -C "$Work_tree_path" ls-files`
git --git-dir="$git_path" --work-tree="$stage_backup" add .
git -C "$Work_tree_path" rm -r --force --ignore-unmatch --quiet -- "$stage_backup" \
; rm -rf "$stage_backup"
これらは、以下で代用できるかもしれない(ただし、work_tree も消える可能性がある)。
(※[-S --staged] は "Git 2.35" 以上)
・git stash push --staged --all --message "stage_backup"
・git stash pop --index