過去のバージョンの記録から抹殺する。

晴天の霹靂 gitで管理している過去のバージョンファイルに脆弱性あり

webサーバに置く内容をgitでバージョン管理をしているのだが、githubから「深刻なセキュリティ上の問題があるから対応しなさい」と警告が来るようになった。
警告対象はRuby関連のファイル。
Jekyllでコンテンツを作成していたせいか、Ruby関連のファイルもリポジトリに登録されているからのようだ。

とはいっても、過去のファイルであるし、そもそも今はJekyllでコンテンツを作成していない。
となれば本当に危険なのかどうか、よく分からないがリポジトリからそういった過去のバージョンをまるまる削除することにする。

git rebase

そういったバージョンの操作にはgit rebaseを使うようだ。
以下、手順を記す。

コミットの特定

git log --onelineとし、コミットの一覧を表示させて、削除するコミットを特定する。

$ git log --oneline

f4f4d170 (HEAD, origin/master, origin/HEAD) remove some tags
0154f932 remove some tags
0212779a add some articles
4a38e31c completely rewrited
35594523 rebuilding site Fri Apr 17 18:41:34 JST 2020

上記の355..より後、最新のf4f4より前のコミットを操作したい場合とする。

rebaseの実行

git rebase -i 35594523と実行する。
すると後述のような画面になる。
viと同じ操作ができる。
なお、一番古いコミットから操作をしたい場合には、git rebase -i --rootとする。

コミットの操作

さてgit rebase -iで表示させた画面で作業を行う。

pick 4a38e31c completely rewrited
pick 0212779a add some articles
pick 0154f932 remove some tags
pick f4f4d170 remove some tags

# Rebase 0f54f922..f3f4d160 onto 0f54f922 (2 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified); use -c <commit> to reword the commit message
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.

説明に書いてあるとおり、操作はpickと書かれているコマンドを書き換えたり、あるいは行自体を書き換えることで行う。
この記事で挙げた用途で使うコマンドは、squashfixupの2つ。
squashの場合、コミットメッセージを編集する。
fixupはコミットメッセージも削る。

もし行自体を削除すると、そのコミット自体が無くなる。

git commitやりなおし

:wqでエディタを終了すると、各コミットごとにgit commitのやり直しが始まる。
基本的にはgit add .とし、git commit、コミットメッセージ編集、git rebase --continueを繰り返せばよい。

結構複雑な処理なので、もし途中でやってしもうた場合にはgit rebase --abortでもとに戻せる。

最初のcommitも削除した場合

最初のcommitも削除すると、参照すべきファイルがまったくなくなってしまうので以下のような警告が表示される。
好きな方を選ぶ.

$ git rebase --continue
The previous cherry-pick is now empty, possibly due to conflict resolution.
If you wish to commit it anyway, use:

    git commit --allow-empty

Otherwise, please use 'git rebase --skip'
interactive rebase in progress; onto 6749affd

git pushでリモートに反映

作業が終わったらリモートに反映させる。
git pushするわけだが、ブランチを指定すること。
しかし大工事をしたせいかそのままでは受け付けてもらえない。
そこで--forceオプションで強制的に反映させる。

$ git push origin HEAD:master
Username for 'https://github.com': 
Password for 'https://xxxxx@github.com': 
To https://github.com/xxx/xxx.git
 ! [rejected]          HEAD -> master (non-fast-forward)
error: failed to push some refs to 'https://github.com/xxx/xxxx.git'
hint: Updates were rejected because a pushed branch tip is behind its remote
hint: counterpart. Check out this branch and integrate the remote changes
hint: (e.g. 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
$ git push origin HEAD:master --force

以上