20211230のGitに関する記事は6件です。

kazuo_reve「GitHubを使い始めたときに参照した記事まとめ」に何も付け加えられない私。

GitHubを使い始めたときに参照した記事まとめ に何か付け加えようと思い筆を取りました。 残念ながら、 git ちゃんと使ってない。 そいでもって、GitLab Advent Calendar 2021 14日目の記事はこちら。 公開算譜は機敏だ。前史。 アジャイル開発 Advent Calendar 2021 15日目の記事はこちら。 公開算譜は機敏だ。後書き 公開算譜は機敏だ 公開算譜は機敏だ(An Open Source Project is Agile)GitHub with Docker。Youtube(2) 仮説・検証(51) 人のGithub依存 知り合いのGithubの資料を使わせていただいているだけの現状。 Dockerをどっかーらどうやって使えばいいんでしょう。TOPPERS/FMP on RaspberryPi with Macintosh編 5つの関門 TOPPERS/ATK2カーネル向け実機レス環境(athrill2) Github Open_Source_is_Agile 今年は、まずfollowerを100人にすることから始めた。 何を参考にすればいいか調べるところから。 予定 Githubで開発環境構築から教育環境構築、教材作成へ 5年経つのにまだこんな状況。 設計はgit, dockerで。docker(13) 問題発見、問題解決、再発防止はGithubとDockerで。docker(143) Githubとdocker。docker(59) あとがき(post script) 何も付け加えられなかった。 資料は整理でき、やれていないことが何かが明確になり、過去の予定も、将来の予定に変換しつつある。 文書履歴(document history) ver. 0.01 初稿 20211230 ver. 0.02 加筆 20211231
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitのPackfileの中身を見てみる

前提 公式サイトのBookにある説明を読んでいるものとしています 10.2 Gitオブジェクト 10.3 Gitの参照 10.4 Packfile この記事は公式の説明pack-formatを参考に Gitのソースコードを読んで確認した内容を示しています あえていうまでもありませんが、内容は保証しません 参考文献 上記Bookとpack-format Gitのソースコード Packfileの記事に書かれていること Packfileにはコミット・ツリー・Blobのいずれも含まれている よく似たオブジェクトは差分化して保存されている pack-formatの記事に書かれていること pack-*.packには次のデータがある char[4]: マジックナンバー"PACK" uint32_t: バージョン uint32_t: オブジェクト数 差分化されていないデータ $n$バイトのヘッダ: $3$-bitのタイプ+${(n-1)\times7 + 4}$-bitのサイズ 圧縮データ 差分化されたデータ 上記と同じようなヘッダ。ただし、タイプはOBJ_REF_DELTA(7)または OBJ_OFS_DELTA(6)である。 このタイプは基準となっているデータを指し示す方法を表す。 - 圧縮された差分データ - .packのチェックサム 差分データの中身は次の二つ 0b1xxxxxxx ...: 基準となっているデータからコピーする 0b11111111 offset1 offset2 offset3 offset4 size1 size2 size3 offset、sizeはリトルエンディアン 直前の操作のあとに、直前のコピーで読み出した位置からoffsetバイト読み飛ばして sizeバイトコピーする - 0b0nnnnnnn ...: データを追加する - 続くnバイトの値を直前の操作の後に書く pack-*.idxには次のデータがある(バージョン2の場合) char[4]: マジックナンバー "\377tOc" uint32_t: バージョン uint32_t[256]: ハッシュ値の第1バイトがidx以下であるpack内のオブジェクトの数 (※公式サイトの図参照) packに格納されたハッシュ値の配列。昇順にソートされている。 uint32_t[n_obj]: CRC32チェックサム(オブジェクトのハッシュ値昇順) uint32_t[n_obj]: オフセット(.packのサイズが4GB以下の場合) (.packのサイズが2GB以上の場合、ここにオフセットの続きが入る) .packのチェックサム .idxのチェックサム pack-*.revやMIDXについては、現物を見たことがないので略 実際に見てみる 適当に作ったGitリポジトリのオブジェクトを実際に読み取ってみる この記事の内容を格納したリポジトリを作って試した。 git fast-import用のリポジトリデータ(タブがコピペでスペースに化けるので再現できませんが、本旨には関係ないので許してください) % git fast-export --all blob mark :1 data 954 GitのPackfileの中身を見てみる # 前提 * 公式サイトのBookにある説明を読んでいるものとしています - [10.2 Gitオブジェクト](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88) - [10.3 Gitの参照](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%81%AE%E5%8F%82%E7%85%A7) - [10.4 Packfile](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Packfile) * この記事は公式の説明[pack-format](https://git-scm.com/docs/pack-format)を参考に Gitのソースコードを読んで確認した内容を示しています * あえていうまでもありませんが、内容は保証しません # Packfileの記事に書かれていること * Packfileにはコミット・ツリー・Blobのいずれも含まれている。 * よく似たオブジェクトは差分化して保存されている reset refs/heads/master commit refs/heads/master mark :2 author Takashi Sakai <sakai@localhost> 1640850064 +0900 committer Takashi Sakai <sakai@localhost> 1640850064 +0900 data 15 initial commit M 100644 :1 a.txt blob mark :3 data 3127 GitのPackfileの中身を見てみる # 前提 * 公式サイトのBookにある説明を読んでいるものとしています - [10.2 Gitオブジェクト](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88) - [10.3 Gitの参照](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%81%AE%E5%8F%82%E7%85%A7) - [10.4 Packfile](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Packfile) * この記事は公式の説明[pack-format](https://git-scm.com/docs/pack-format)を参考に Gitのソースコードを読んで確認した内容を示しています * あえていうまでもありませんが、内容は保証しません # Packfileの記事に書かれていること * Packfileにはコミット・ツリー・Blobのいずれも含まれている * よく似たオブジェクトは差分化して保存されている # pack-formatの記事に書かれていること * ```pack-*.pack```には次のデータがある - ```char[4]```: マジックナンバー"PACK" - ```uint32_t```: バージョン - ```uint32_t```: オブジェクト数 - 差分化されていないデータ - nバイトのヘッダ: 3-bitのタイプ+{(n-1)*7 + 4}-bitのサイズ - 圧縮データ - 差分化されたデータ - 上記と同じようなヘッダ。ただし、タイプは```OBJ_REF_DELTA```(7)または ```OBJ_OFS_DELTA```(6)である。 このタイプは基準となっているデータを指し示す方法を表す。 - 圧縮された差分データ - ```.pack```のチェックサム * 差分データの中身は次の二つ - ```0b1xxxxxxx ...```: 基準となっているデータからコピーする - ```0b11111111 offset1 offset2 offset3 offset4 size1 size2 size3``` - ```offset```、```size```はリトルエンディアン - 直前の操作のあとに、直前のコピーで読み出した位置から```offset```バイト読み飛ばして ```size```バイトコピーする - ```0b0nnnnnnn ...```: データを追加する - 続くnバイトの値を直前の操作の後に書く * ```pack-*.idx```には次のデータがある(バージョン2の場合) - ```char[4]```: マジックナンバー "\377tOc" - ```uint32_t```: バージョン - ```uint32_t[256]```: ハッシュ値の第1バイトがidx以下であるpack内のオブジェクトの数 (※[公式サイトの図](https://git-scm.com/docs/pack-format#_original_version_1_pack_idx_files_have_the_following_format)参照) - ```uint32_t[n_obj]```: CRC32チェックサム(オブジェクトのハッシュ値昇順) - ```uint32_t[n_obj]```: オフセット(```.pack```のサイズが4GB以下の場合) - (```.pack```のサイズが2GB以上の場合、ここにオフセットの続きが入る) - ```.pack```のチェックサム - ```.idx```のチェックサム * ```pack-*.rev```や```MIDX```については、現物を見たことがないので略 commit refs/heads/master mark :4 author Takashi Sakai <sakai@localhost> 1640851556 +0900 committer Takashi Sakai <sakai@localhost> 1640851556 +0900 data 14 add some text from :2 M 100644 :3 a.txt 対象のオブジェクトを決める。 % git verify-pack -v .git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack bd662ac2ac6b1225be7772779424870aae89fdfb commit 224 154 12 2e3d72440b11dbb1d4ec46ff75d7bc4a550cfdc5 commit 177 121 166 44126f1961c05cf7c640a1da57128dac91007668 blob 3127 1355 287 7721218b8e626bd5fb8510df87e5b3d070e548c9 tree 33 44 1642 3431f58b1fdac86856bbf5a6dd9ed5186646d9fa tree 33 46 1686 a4ebaf4caaf976aac558dcacfa4ec9d692cafaf3 blob 15 26 1732 1 44126f1961c05cf7c640a1da57128dac91007668 non delta: 5 objects chain length = 1: 1 object .git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack: ok 差分化されたものを例にしたいのでa4ebaf4caaf976aac558dcacfa4ec9d692cafaf3を 使う 前節の説明より、.packの方をいきなり見ても、ほとんどの部分は圧縮データなのでデータの起点が特定できない(頭から順に読んでいけば読み出せるが面倒なのでやらない。) インデックス編 まず.idxで目的のデータを探す .idxの内容 # t O c ver. 2 0000000 ff 74 4f 63 00 00 00 02 # 4バイト整数256個 0000008 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 (snip) 00000a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00000b8 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 01 00000c8 00 00 00 01 00 00 00 01 00 00 00 01 00 00 00 01 00000d8 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 (snip) 0000108 00 00 00 02 00 00 00 02 00 00 00 02 00 00 00 02 0000118 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 03 (snip) 00001d8 00 00 00 03 00 00 00 03 00 00 00 03 00 00 00 04 00001e8 00 00 00 04 00 00 00 04 00 00 00 04 00 00 00 04 (snip) 0000288 00 00 00 04 00 00 00 04 00 00 00 04 00 00 00 04 0000298 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 (snip) 00002e8 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 00002f8 00 00 00 05 00 00 00 06 00 00 00 06 00 00 00 06 0000308 00 00 00 06 00 00 00 06 00 00 00 06 00 00 00 06 (snip) 00003f8 00 00 00 06 00 00 00 06 00 00 00 06 00 00 00 06 # オブジェクトハッシュ(6件、昇順、各20(0x14)バイト) 0000408 2e 3d 72 44 0b 11 db b1 d4 ec 46 ff 75 d7 bc 4a 0000418 55 0c fd c5 000041c 34 31 f5 8b 1f da c8 68 56 bb f5 a6 dd 9e d5 18 000042c 66 46 d9 fa 0000430 44 12 6f 19 61 c0 5c f7 c6 40 a1 da 57 12 8d ac 0000440 91 00 76 68 0000444 77 21 21 8b 8e 62 6b d5 fb 85 10 df 87 e5 b3 d0 0000454 70 e5 48 c9 0000458 a4 eb af 4c aa f9 76 aa c5 58 dc ac fa 4e c9 d6 0000468 92 ca fa f3 000046c bd 66 2a c2 ac 6b 12 25 be 77 72 77 94 24 87 0a 000047c ae 89 fd fb # CRC32(6件、同順、各4バイト) 0000480 96 64 8d b1 5c b3 6c 97 a2 f3 5d 6e 08 fc a5 8a 0000490 40 d2 d9 59 9d 23 99 de # オフセット(6件、同順、各4バイト) 0000498 00 00 00 a6 00 00 06 96 00 00 01 1f 00 00 06 6a 00004a8 00 00 06 c4 00 00 00 0c # packハッシュ 00004b0 6b 39 32 9a ed 24 19 0a a8 35 8b 85 f1 0d 1c 0e 00004c0 52 84 51 d7 # idxハッシュ 00004c4 9d 10 22 6c 21 e5 7a 12 55 d3 e4 b5 08 10 0f ff 00004d4 db ed 77 cb 今回探すのはa4ebaf4caaf976aac558dcacfa4ec9d692cafaf3なので 0xA4(164)-1番目の整数を見てみる。 0xA3 × 4 = 0x28c。起点が0x8なので0x294を見る。 0000288 00 00 00 04 00 00 00 04 00 00 00 04 00 00 00 04 ^^^^^^^^^^^ 0000298 00 00 00 05 00 00 00 05 00 00 00 05 00 00 00 05 (略) 00003f8 00 00 00 06 00 00 00 06 00 00 00 06 00 00 00 06 00 00 00 04である。 よって、a4〜〜というハッシュのオブジェクトは4番目から始まるとわかる。 また、データの総数もわかる。最後(256番目)の整数が00 00 00 06なので 総数は6である。 この情報を参考に、a4ebaf4caaf976aac558dcacfa4ec9d692cafaf3を探す。 4バイト整数256個が終わるのは0000408。ここからハッシュ値の配列が続く。 このリポジトリのハッシュ値はSHA-1なので20バイト(160 bits)。20×4 = 80(0x50)バイト読み飛ばす。 0000458をみるとちょうどそこにa4 eb af 4c ... fa f3がある。 a4ebaf4caaf976aac558dcacfa4ec9d692cafaf3は5番目である。 00003f8 00 00 00 06 00 00 00 06 00 00 00 06 00 00 00 06 # オブジェクトハッシュ(6件、昇順、各20(0x14)バイト) #0 0000408 2e 3d 72 44 0b 11 db b1 d4 ec 46 ff 75 d7 bc 4a 0000418 55 0c fd c5 000041c 34 31 f5 8b 1f da c8 68 56 bb f5 a6 dd 9e d5 18 000042c 66 46 d9 fa 0000430 44 12 6f 19 61 c0 5c f7 c6 40 a1 da 57 12 8d ac 0000440 91 00 76 68 0000444 77 21 21 8b 8e 62 6b d5 fb 85 10 df 87 e5 b3 d0 0000454 70 e5 48 c9 #4 0000458 a4 eb af 4c aa f9 76 aa c5 58 dc ac fa 4e c9 d6 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0000468 92 ca fa f3 ^^^^^^^^^^^ 000046c bd 66 2a c2 ac 6b 12 25 be 77 72 77 94 24 87 0a 000047c ae 89 fd fb これでついに.pack内のアドレスが得られる。 ハッシュ値の配列は0000408から始まって、20バイト×6個、120(0x78)バイトである。 よって、次のデータは0000480から始まる。 続くのはCRC32のチェックサムである。これは今回使わないので読み飛ばす。 4バイト×6個=24(0x18)バイト読み飛ばして、次は0000498から始まる。 次がまさに求めている.pack内のアドレスである。 この5番目を読みたいので4個=16(0x10)バイト飛ばす。00004A8 00004a8には00 00 06 c4と書いてある。アドレスゲットである。 # CRC32(6件、同順、各4バイト) 0000480 96 64 8d b1 5c b3 6c 97 a2 f3 5d 6e 08 fc a5 8a 0000490 40 d2 d9 59 9d 23 99 de # オフセット(6件、同順、各4バイト) 0000498 00 00 00 a6 00 00 06 96 00 00 01 1f 00 00 06 6a 0 1 2 3 00004a8 00 00 06 c4 00 00 00 0c 4^^^^^^^^^^ 5 同じ要領でこのオブジェクトの元のオブジェクト44126f1961c05cf7c640a1da57128dac91007668のアドレスも取得すると、0x11fである。 わかりやすさのため、まずこの0x11fを読んでみる。 普通オブジェクトの中身 先ほどのインデックスのオフセットのリストを見てみると0x11fの次は0x66aから始まるとわかる。 0000498 00 00 00 a6 00 00 06 96 00 00 01 1f 00 00 06 6a 00004a8 00 00 06 c4 00 00 00 0c (0x11fの次に小さい値は0x66aになっている。) .packから0x11fから0x66a(1642)を取り出してみる % head -c 1642 .git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack | hexdump -s 0x11f 000011f b7 c3 01 78 9c ad 56 6b 53 1a 57 18 fe 1c 7e c5 000012f 8e 19 66 c4 0c 20 17 85 fa 0d 0c 3a e9 65 cc a4 (snip) 000064f 51 5f fa 8d 7f fd 67 94 4f 07 b6 83 d8 49 4b 85 000065f 27 5b df d8 37 fc 05 5a c3 3b c7 b7 c3 01は「3127バイトのBlob」を表している b7 (0b1_011_0111): タイプ=3(OBJ_BLOB), サイズ=0b...0111 c3 (0b1_1000011): サイズ=0b...1000011_0111 01: サイズ = 0b0000001_1000011_0111 = 0xC37(3127) 中身 この後はDeflate圧縮したデータが入っている。例えばpigzコマンドをインストールして、 これを使うことで伸長できる 今回のリポジトリはこの記事のテキストの序盤を入れて作っているので、このような内容が出てくる。 % dd bs=1 skip=0x122 count=0x548 \ if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack \ 2>/dev/null | pigz -dc GitのPackfileの中身を見てみる # 前提 * 公式サイトのBookにある説明を読んでいるものとしています (snip) looseオブジェクトにおけるblob (サイズ)\0のヘッダはついていない。 これは、type情報と重複するためと考えられる。 差分オブジェクトの読み出し 先ほど取得したアドレス0x6c4をpackファイルから読み出してみる。 % cat .git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack | hexdump -s 0x6c4 00006c4 6f 8a 25 78 9c db 2e b1 8b 7d 43 1e 33 f3 e3 86 00006d4 a6 c9 79 cc 9e 00 31 91 05 e7 6b 39 32 9a ed 24 00006e4 19 0a a8 35 8b 85 f1 0d 1c 0e 52 84 51 d7 00006f2 .packの末尾20(0x14)バイトは.pack自身のチェックサムなので今回はいらない。削る。 0x6f2 - 0x14 = 0x6de = 1758 % head -c 1758 .git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack | hexdump -s 0x6c4 00006c4 6f 8a 25 78 9c db 2e b1 8b 7d 43 1e 33 f3 e3 86 00006d4 a6 c9 79 cc 9e 00 31 91 05 e7 00006de たった26バイトで差分が表現されている。 こちらも最初はヘッダである。 6f = タイプ6(OBJ_OFS_DELTA), サイズf(15) 見ての通りこのデータのサイズは15バイトではない。 このサイズは伸長後のサイズなので、一致しない。 Deflate圧縮をかけているのだが、今回の差分は単純すぎるので、逆に容量が増してしまっている。 OBJ_OFS_DELTAの場合、元になっているオブジェクトとこのオブジェクト自身のアドレスの差が 続いて書かれている。: 8a 25 この値は、offset encodingで符号化されている。 ドキュメントにも説明されているが、たぶんソースを見たほうがわかりやすい。 8a: 最上位ビットが1である場合、この7ビットで値が表しきれないことを示す。 まずは、このバイトで表すビットを取り出す。 0x8a & 0x7f = 0xa 表しきれないのだから、ここに1を足す。 0xa + 1 = 0xb 7ビット左シフトする。 0xb << 7 = 0x580 25: 最上位ビットが0である場合、これが最後であることを示す。 0x580 | 0x25 = 0x5a5 この値を今見ている項目のアドレスから引く。0x6c4 - 0x5a5 = 0x11f 先ほどの0x11fのオブジェクトのデータがこの差分の元になっていることを確認できた。 6f及び8a 25は「これが差分であること」と「元データは0x11fにあること」を示すのに 使われているので、差分データ本体ではない。 続く0x6c7〜0x6deが差分を表している。 差分データ本体はDeflate圧縮されている。伸長し表示してみる。 % dd bs=1 if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack skip=0x6c7 count=0x17 2>/dev/null | pigz -dc | hexdump 0000000 b7 18 ba 07 b0 6e 03 03 e3 80 82 93 6e 03 49 000000f 差分データの中身 差分データそのものの構造は前掲のドキュメントがわかりやすい 今回の差分オブジェクトで表されている差分をdiffで表すと次の通りである。 この差分に対応するdiff diff --git a/44126f1961c05cf7c640a1da57128dac91007668 b/a4ebaf4caaf976aac558dcacfa4ec9d692cafaf3 index 44126f1..a4ebaf4 100644 --- a/44126f1961c05cf7c640a1da57128dac91007668 +++ b/a4ebaf4caaf976aac558dcacfa4ec9d692cafaf3 @@ -1,48 +1,14 @@ GitのPackfileの中身を見てみる # 前提 * 公式サイトのBookにある説明を読んでいるものとしています - [10.2 Gitオブジェクト](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%82%AA%E3%83%96%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88) - [10.3 Gitの参照](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Git%E3%81%AE%E5%8F%82%E7%85%A7) - [10.4 Packfile](https://git-scm.com/book/ja/v2/Git%E3%81%AE%E5%86%85%E5%81%B4-Packfile) * この記事は公式の説明[pack-format](https://git-scm.com/docs/pack-format)を参考に Gitのソースコードを読んで確認した内容を示しています * あえていうまでもありませんが、内容は保証しません # Packfileの記事に書かれていること -* Packfileにはコミット・ツリー・Blobのいずれも含まれている +* Packfileにはコミット・ツリー・Blobのいずれも含まれている。 * よく似たオブジェクトは差分化して保存されている - -# pack-formatの記事に書かれていること -* ```pack-*.pack```には次のデータがある - - ```char[4]```: マジックナンバー"PACK" - - ```uint32_t```: バージョン - - ```uint32_t```: オブジェクト数 - - 差分化されていないデータ - - nバイトのヘッダ: 3-bitのタイプ+{(n-1)*7 + 4}-bitのサイズ - - 圧縮データ - - 差分化されたデータ - - 上記と同じようなヘッダ。ただし、タイプは```OBJ_REF_DELTA```(7)または - ```OBJ_OFS_DELTA```(6)である。 - このタイプは基準となっているデータを指し示す方法を表す。 - - 圧縮された差分データ - - ```.pack```のチェックサム -* 差分データの中身は次の二つ - - ```0b1xxxxxxx ...```: 基準となっているデータからコピーする - - ```0b11111111 offset1 offset2 offset3 offset4 size1 size2 size3``` - - ```offset```、```size```はリトルエンディアン - - 直前の操作のあとに、直前のコピーで読み出した位置から```offset```バイト読み飛ばして - ```size```バイトコピーする - - ```0b0nnnnnnn ...```: データを追加する - - 続くnバイトの値を直前の操作の後に書く -* ```pack-*.idx```には次のデータがある(バージョン2の場合) - - ```char[4]```: マジックナンバー "\377tOc" - - ```uint32_t```: バージョン - - ```uint32_t[256]```: ハッシュ値の第1バイトがidx以下であるpack内のオブジェクトの数 - (※[公式サイトの図](https://git-scm.com/docs/pack-format#_original_version_1_pack_idx_files_have_the_following_format)参照) - - ```uint32_t[n_obj]```: CRC32チェックサム(オブジェクトのハッシュ値昇順) - - ```uint32_t[n_obj]```: オフセット(```.pack```のサイズが4GB以下の場合) - - (```.pack```のサイズが2GB以上の場合、ここにオフセットの続きが入る) - - ```.pack```のチェックサム - - ```.idx```のチェックサム -* ```pack-*.rev```や```MIDX```については、現物を見たことがないので略 オリジナルバージョンと、「。」を消しいくらか文章を追加したバージョンの差分 差分の効率や最新版の読み取り性能を高めるためなどの理由で、gitはこれを追加版と追加版に対するパッチとして表したオリジナル版、 という形で保持している。 0000000 b7 18 ba 07 b0 6e 03 03 e3 80 82 93 6e 03 49 最初は差分適用前後のファイルサイズが書かれている。 元サイズb7 18 (0b1_0110111 0b0_0011000) = 0b0011000_0110111 = 0xc37 後サイズb0 07 (0b1_0110000 0b0_0000111) = 0b0000111_0110000 = 0x3b0 後はコピー命令か追記命令が並ぶ。 最初はb0 6e 03 b0 = 0b10110000 最上位ビットが1のものはコピー命令。元データの一部をコピーする。 これを逆順に並べてみる。0000 110 (1) 最初(LSB)がオフセット量最下位バイト、2番目がオフセット量の下から2番目のバイト、 ……の存在を示すので、オフセット量が0であることが読み取れる。 また、5番目(第4ビット)がサイズの最下位、6番目が下から2番目、7番目が下から3番目を示して、 コピーサイズが2バイトあることも読み取れる。 続く指定を読み取る。 6e 03 = コピーサイズ: 0x36e GitのPackfileの中身を見てみる (略) # Packfileの記事に書かれていること * Packfileにはコミット・ツリー・Blobのいずれも含まれている 次は03 e3 80 82 3バイト即値で加える。 e3 80 82 = UTF-8で"。" -* Packfileにはコミット・ツリー・Blobのいずれも含まれている +* Packfileにはコミット・ツリー・Blobのいずれも含まれている。 次は93 6e 03 49 93 = 0b1_001_0011 6e 03: オフセット = 0x036e 49: サイズ = 0x49 * よく似たオブジェクトは差分化して保存されている - -(略) おまけ .packの末尾20バイトは.packのそれまでの部分のチェックサムが書かれている。チェックしてみる。 今回の.packのサイズは0x6f2だから、チェックサムの始点は0x6de。 これはファイル名(pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack)とも一致する。 % dd if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack bs=1 skip=0x6de 2>/dev/null | hexdump 0000000 6b 39 32 9a ed 24 19 0a a8 35 8b 85 f1 0d 1c 0e 0000010 52 84 51 d7 % dd if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.pack bs=1 count=0x6de 2>/dev/null | shasum 6b39329aed24190aa8358b85f10d1c0e528451d7 - .idxの最後から40バイト目〜20バイト目にも同じことが書かれている。 今回の.idxのサイズは0x4d8だから、0x4b0+0x14を見れば良い % dd if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.idx bs=1 skip=0x4b0 count=0x14 2>/dev/null | hexdump 0000000 6b 39 32 9a ed 24 19 0a a8 35 8b 85 f1 0d 1c 0e 0000010 52 84 51 d7 .idxの末尾20バイトは.idxのそれまでの部分のチェックサムが書かれている。 今回の.idxのサイズは0x4d8だから、チェックサムの始点は0x4c4。 % dd if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.idx bs=1 skip=0x4c4 2>/dev/null | hexdump 0000000 9d 10 22 6c 21 e5 7a 12 55 d3 e4 b5 08 10 0f ff 000010 db ed 77 cb % dd if=.git/objects/pack/pack-6b39329aed24190aa8358b85f10d1c0e528451d7.idx bs=1 count=0x4c4 2>/dev/null | shasum 9d10226c21e57a1255d3e4b508100fffdbed77cb -
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

npm run buildの際にBuilding for production...Errorが出る

久々の投稿です、 現在は、派遣でエンジニアしてます。 来年の2月からフリーランスになります!! 次の現場では、vueを使うので勉強していて 問題にぶつかりました。 npm run build時に下記のエラーが出ました。 kushiyama_makoto@MakotonoMacBook-Air udemy-vuejs % npm run build > udemy-vuejs@0.1.0 build > vue-cli-service build ⠹ Building for production...Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19) at Object.createHash (node:crypto:130:10) at module.exports (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/util/createHash.js:135:53) at NormalModule._initBuildHash (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:417:16) at handleParseError (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:471:10) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:503:5 at /Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:358:12 at /Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:373:3 at iterateNormalLoaders (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:214:10) at iterateNormalLoaders (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:221:10) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:236:3 at runSyncOrAsync (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:130:11) at iterateNormalLoaders (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:232:2) at Array.<anonymous> (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:205:4) at Storage.finished (/Users/kushiyama_makoto/udemy-vuejs/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:55:16) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/enhanced-resolve/lib/CachedInputFileSystem.js:91:9 /Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:114 throw e; ^ Error: error:0308010C:digital envelope routines::unsupported at new Hash (node:internal/crypto/hash:67:19) at Object.createHash (node:crypto:130:10) at module.exports (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/util/createHash.js:135:53) at NormalModule._initBuildHash (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:417:16) at handleParseError (/Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:471:10) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:503:5 at /Users/kushiyama_makoto/udemy-vuejs/node_modules/webpack/lib/NormalModule.js:358:12 at /Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:373:3 at iterateNormalLoaders (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:214:10) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:186:6 at context.callback (/Users/kushiyama_makoto/udemy-vuejs/node_modules/loader-runner/lib/LoaderRunner.js:111:13) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/cache-loader/dist/index.js:240:7 at /Users/kushiyama_makoto/udemy-vuejs/node_modules/neo-async/async.js:2830:7 at done (/Users/kushiyama_makoto/udemy-vuejs/node_modules/neo-async/async.js:2865:11) at /Users/kushiyama_makoto/udemy-vuejs/node_modules/neo-async/async.js:2818:7 at Array.<anonymous> (/Users/kushiyama_makoto/udemy-vuejs/node_modules/cache-loader/dist/index.js:229:9) { opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ], library: 'digital envelope routines', reason: 'unsupported', code: 'ERR_OSSL_EVP_UNSUPPORTED' } Node.js v17.3.0 正直わからん状態でしたが、ググった結果下記のコマンドで解決しました。 export NODE_OPTIONS=--openssl-legacy-provider nodeの設定を追加したみたいですね。 一応、下記のURLを参考にしました。 https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported 確認してみてください!!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Git_基本操作①

はじめに 場面別にGitコマンドをまとめていきます. モチベがあれば続きます. ※筆者はGit初学者のため、間違い等がある場合は優しめにコメント頂けますと助かります…! 場面① リモートからローカルにリポジトリを複製する コマンド git clone <remote_url> 指定先urlのリモートリポジトリからローカルに対してリポジトリを複製 通信時のプロトコルは主にhttps もしくは sshを使用 認証方法などが異なる. その場に応じて適切なプロトコルを選択すること 例. 場面② ローカルでの作業後に作業内容をリモートへアップロードする コマンド git status 現在の状態を確認するコマンド gitに管理されていないファイルは赤字で表示(ステージングされていない状態) gitに管理されているファイルは緑字で表示(ステージングされた状態) コマンド git add <file_name> 特定のファイルをgitに管理(登録)させたい時に使用 全てのファイル(git statusで赤字表示されている全てのファイル)をgitに管理させたい時は「git add .」を使用 例. コマンド git commit -m <commit_message> 現在の状態をgitにセーブ(保存)したい時に使用 「commit_message」にコミット時のメッセージ内容を記載 例. ※コミット後に同ファイルの編集を行った場合は再度、addとcommit操作が必要 コマンド git log gitのコミット履歴を確認出来るコマンド 何時何分に誰がコミットしたという記録が残る 例. コマンド git push <remote> <branch> // 現在チェックアウトしているブランチを、その上流ブランチに push git push origin // ローカルブランチ「master」を、「origin」上の同名のブランチに反映する git push origin master // ローカルブランチ「master」を、リモートブランチ「master」に push git push origin master:master リモートにアップロードを行いたい時に使用 origin:リモートサーバのこと 第2引数に「:(コロン)」を用いれば、push 先となるリモートブランチを明示的に指定する事が可能 push前: push後: コミット履歴: 1回目のコミット内容: 2回目のコミット内容: まとめ メイン a b git clone リモートリポジトリの内容をローカルに複製 git add gitに管理(登録) git commit gitにセーブ(保存) git push リモートにアップロード(反映) サポート a b git status 現在の状態を確認 git log コミット履歴を確認
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

git reset解説

以下は社内向け勉強会のLT枠で話した内容をベースにして編集増補したものである。増補しただけでなくそもそも1回分を記事にしたものではなかったりもするので、この内容を5分で話したわけではない。 git resetコマンドの概要 「HEADが参照しているブランチの参照しているコミットを変更」するコマンド git checkout(git restore)でできるような「ファイルの復元」も行うこともできるが、git checkout(git restore)とは元々の守備範囲が異なるので全く同じことができるわけではない 立ち位置としてはgit checkout(git restore)がgit addの逆操作のコマンドであり、git resetはgit commitの逆操作のコマンドである。もっとも、どちらもその領域を超えた機能も持っているわけだが。 git resetは良く「コミットの取り消しを行うコマンド」として紹介されているが、本質的には上に書いた通りのHEADが参照しているブランチ、つまり作業者から見れば現在作業中のブランチの参照している「コミットを変更するコマンド」である。変更先のコミットに指定できるのは、リポジトリ内に存在するコミットならどれでも任意なので、コミット履歴の1つ前のコミットに移動すれば「コミットの取り消し」が行われているように見え、またその使い方がgit resetにとって最もポピュラーなので「コミットの取り消し」をするコマンドと紹介されることが多いわけである。実際のところは履歴の100個前のコミットにでも、履歴に載っていないコミットにでも移動可能である。 HEADが参照しているブランチの参照しているコミットを変更 HEADが参照しているブランチのコミットを変更するコマンドは以下である。 git reset <モード> <変更先commit-ish> コマンドを見ればわかるように、この形式ではファイル名は指定できないのでリポジトリ全体のファイルに対する処理となる。もっとも、全体とは言ってもgit checkoutやgit restoreと同様、git管理外のファイル(これにはインデックスにもいずれのコミットにも含まれていないファイル、つまりgit statusで"Untracked files"に表示されるものも含む)が変更されることはない。 モードは独立した項目で説明する。 変更先はcommit-ishが指定できる。つまり純粋なコミットIDだけでなく、"HEAD^"等としてHEADの1つ前のコミットを指定するのが良く見られる形である。 変更先にはそれ以外にも「コミットの打ち消しの打ち消し」として良く紹介される"HEAD@{1}"としてreflogの最新の1つ前を指定する、というのもある。git resetは、実体がリファレンスである、ブランチのコミットを変更するコマンドなので、この形式で行われたすべての実行履歴がリファレンスの操作ログであるreflogに記録される。よって先程実行したgit resetによるコミットの変更を元に戻したければreflogの最新の1つ前を指定すれば良い、ということになる。reflogの各履歴はコミットへの参照を持つのでcommit-ishである。 reflogに記録されるのはこの作業者のローカルのリポジトリで行った操作だけであるが、git resetだけが記録されるわけではないので、1つ前と決め込まずにgit reflogでいくつ前の実行履歴だったか確認した方が良い。人間はパニックになった時はわけのわからない操作をすることもあるのである。 git resetコマンドのモード git resetコマンドのモードは、HEADが参照するコミットを変更した後、ついでに何をするかを指定するものであり、--soft、--mixed、--hard、--keep、--mergeの5つのうち1つを選択する。デフォルトは--mixedなので何も指定していなければ--mixedが指定されている扱いとなる。メジャーなのは--soft、--mixed、--hardの3つで、後の2つ、--keep、--mergeはあまり使われていないと思われる。 念を押すと、どのモードであってもHEADが参照するコミットの変更処理は行われる(もちろん、移動前と移動先のコミットが同じなら実質的には変更は発生しない)。モードはあくまでHEADが参照するコミットの変更以外に何をするか、を決めるものである。 「何をするか」というのは具体的にはインデックスやワークツリーのファイルをどうするか、である。インデックスやワークツリーについてはgit checkoutの記事にて説明している。大雑把に言えばgit addする前の作業するための場所がワークツリー、git addした後のファイルの置き場がインデックスである。 モードが--softの場合はHEADが参照するコミットを変更するだけで、インデックスやワークツリーのファイルには変更は加えない。 モードが--mixedの場合はHEADが参照するコミットを変更し、加えてその移動先コミットのファイル内容にインデックスを変更する。ワークツリーのファイルには変更は加えない。 モードが--hardの場合はHEADが参照するコミットを変更し、加えてその移動先コミットのファイル内容にインデックスとワークツリーを変更する。 --hardはよく使われる割に作業中のファイルが全部リセットされる危険なモードである。--hardで消えてしまった作業中だったコミットされていない変更はreflogの履歴等を使って元のコミットに移動しても帰ってくることはない。コミットの内容を元にコピーされるのだから当然である。せめてインデックスに登録してあったならgit fsck --lost-foundでコミットされなかった、かつてインデックスにだけあったファイル内容が(git gcあるいはgit gcを暗黙的に実行する別のコマンド等でまだ掃除されてなければ).git/lost-foundディレクトリの中に書かれるのでそこから探すことができる。ファイル名は保持されていないので内容で探すこと。インデックスにも登録されていなければgitの力による復旧はできない。 この問題はgit checkout(git restore)でも発生するが、git reset --hardで良くやられているのはコマンド自体の知名度によるものだろうか。 --keepというモードは--hardの危険性を多少緩和するものである。HEADが参照するコミットを変更する以外に何が起こるかというと、まず--mixedと同じくインデックスが移動先コミットの内容に書き換えられるのは確定なのだが、ワークツリーに関しては移動先コミットの内容に書き換えられるファイルとそのままにされるファイルとに分かれる。また、それぞれのファイルの移動元コミット、移動先コミット、インデックス、ワークツリーの内容によってはコマンドがエラーとなり失敗することがある。manの説明文に書かれている内容からは微妙に異なる結果が出た(というか、説明が足りない?)ので、以下に表にまとめる。 git reset --keepの結果(ファイルごとに判定される。凡例を以下に示す) 同じ大文字アルファベットや同じ数字は同じ内容のファイルを示す 違う大文字アルファベットはそれぞれ違う内容のファイルを示す 数字は任意のファイルの意味で、いずれかの大文字アルファベットのファイルや他の数字の内容と同じでも違っても良い 「後のワークツリー」の太字は--hard相当のパターン、斜字は--mixed相当のパターン エラーaのメッセージは「error: Entry '<ファイル名>' not uptodate. Cannot merge.」 エラーbのメッセージは「error: Entry '<ファイル名>' would be overwritten by merge. Cannot merge.」 移動元 移動先(=非エラー時、後のインデックス) 元のインデックス 元のワークツリー 後のワークツリー A A 2 1 1 A B A A B A B A A以外 (エラーa) A B B 1 1 A B C 1 (エラーb) ワークツリーが移動先コミットの内容に書き換えられるのは移動元コミットと移動先コミットで内容が異なり、インデックスとワークツリーが共に移動元コミットの内容と同じ、言い換えると編集中ではないファイルである。そのままにされるのは移動元コミットと移動先コミットとで内容が同じか移動先コミットとインデックスとで内容が同じファイルである。このような条件下で変更作業中のファイルでもその変更内容を残すようにしたもの、と考えることができる。 --mergeモードはまず--mixedと同じくインデックスが移動先コミットの内容に書き換えられるところまでは--keepとも同じで、ワークツリーに関してはインデックスとワークツリーが同じなら--hardと同じで、移動先コミットとインデックスが同じ時は--mixedと同じになる。それ以外の場合はエラーとなる。--keepよりは--hard寄りと言えるだろう。こちらはmanの説明文通りの結果が出たが以下に表にまとめる。 git reset --mergeの結果(ファイルごとに判定される。凡例は--keepと同じ) 移動元 移動先(=非エラー時、後のインデックス) 元のインデックス 元のワークツリー 後のワークツリー A A 1 1 A A A C C以外 (エラーa) A 2 2 1 1 A B A A B A B A A以外 (エラーa) A B C C B A B C C以外 (エラーa) 正直--mergeは何故こういう仕様なのか使いどころがわからない。まだ--keepの方は使うこともあるかも、という気分にはなる。 インデックスのファイルの復元 git resetには以下のようなもう1つの形式がある。この形式では指定したファイルをインデックスにおいて復元元の内容と同じにする。 git reset [<復元元tree-ish>] [--] <ファイル名>... 復元元として指定するtree-ishについては、git checkoutのページの方で説明している。省略時はHEADである。 ファイル名は複数指定、ワイルドカード、「.」(カレントディレクトリとサブディレクトリにあるすべてのファイル、の意味)も指定可能である。 今度はファイル名は指定できるがモードを指定できない。git checkoutでも上記コマンドのresetの部分をcheckoutにしただけの同じ形式のコマンドがある。効果は異なり、git resetだと復元されるのはインデックスであるのに対して、git checkoutだと復元されるのはインデックスとワークツリーの両方である(但し、復元元省略時は復元元はインデックスで復元先はワークツリーのみ)。つまりgit resetの方はgit restore [-s <復元元tree-ish>] -S [--] <ファイル名>...と同じ効果であり、git checkoutの方は復元元が省略されていなければgit restore [-s <復元元tree-ish>] -S -W [--] <ファイル名>...と同じ効果である。 この形式ではHEADが参照しているブランチのコミットの変更は発生しない。よってリファレンスへの操作が起こらないのでreflogにも記録されない。 コミットの削除 ここからはgit resetの話からはちょっと離れるが、類似する話題として取り上げる。 git reset <モード> <変更先commit-ish>は「コミットの取り消し」ではなく「HEADが参照しているブランチの参照しているコミットの変更」であると先に述べた。つまりこのコマンドを実行しても直ちにコミット自体が削除されるわけではない。直ちに~ではない、というのは先に書いたようにgit gcあるいはgit gcを暗黙的に実行する別のコマンド等で削除されることはある、という意味である。その場合でもわざわざ保護期間をなしにしておかない限りすぐに消えたりはしないが。 しかしながら、パスワード等の機密情報を含めてしまった、Gitで管理したくないとても大きなファイルを含めてしまった等の理由で1つ前のコミットに戻ってやり直すだけでは済まず、ディスクに書き込まれた情報ごと本当にコミットを削除しなければならない時がある。パスワードなら変更したりキーなら無効化したりして1つ前のコミットに戻ってやり直す方が簡単ならそうした方が良いが。 コミットを削除するには何に対して作業を行われなければならないだろうか。凡そ書き出してみると以下のようなものになる。 コミット自身の削除 削除されるコミットが参照しているツリーに含まれる一連のファイルの削除。但し残されるコミットのツリーにも含まれるファイルは除く (削除されるのが履歴の途中のコミットなら)コミットの履歴の繋がりの修正 削除されるコミットを参照しているブランチやタグといったリファレンス等の書き換え 削除されるコミットを参照しているreflogの削除 もしコミットの削除ではなく、コミット内の一部のファイルの書き換えを行ったとしても、コミットIDが変更されるので大体同じような作業となる。 これだけいろいろやるのは大変であるので普通はそれ用のツールを使って削除することになる。Git標準ではこの用途に使えるgit filter-branchというサブコマンドが提供されていたが今は非推奨となっているので、代わりにサードパーティ製のツールを使用する。GitHubのドキュメントの「Removing sensitive data from a repository」というページにはそれらのツールが紹介されている。Python製のgit filter-repoとJava製のBFG Repo-Cleanerである。 ここではgit filter-repoを使ったやり方を紹介する。git filter-repoの実行にはPython 3.5以上とGit 2.24以上(最小では2.22以上と書かれているが、2.24と比べて何ができなくなるのか良くわからない)が必要である。 削除したいコミットがまだプッシュされていない場合 まずはまだ状況的にマシな、リポジトリが自分が持つ1つしかないか、まだ削除したいコミットをプッシュしておらず自分のローカルにしかない場合について説明する。 現在ワークツリーで作業中のファイルがあれば仮のコミットを作って退避する。その後、git filter-repoは-fオプションを付けない限り、クローンしてすぐのリポジトリで実行しないとエラーとなるのでまず、適当な新しいディレクトリにクローンする。元のリポジトリのルートにいるものとした場合、 git clone --no-local . ../cloned cd ../cloned で、新しいリポジトリで作業することになる。--no-localオプションを付けてgit cloneしないとgit filter-repoは-fオプションを付けろとエラーを出す。リポジトリの大きさ等の理由でクローンするのが現実的でない場合は-fオプションを付けてgit filter-repoをすることになるが、その場合でもバックアップをしてから実行することをお勧めする。リポジトリのディレクトリを丸ごとコピーを取れていればそれでバックアップになる。以下ではgit filter-repoには-fオプションを付けない形で記述する。 例えば新しいリポジトリである特定のファイルをすべてのコミットから削除する場合、以下を実行する。--invert-pathsを付けるのを忘れると--pathで指定したファイル以外が全部削除されるので注意。なお、コミットの中に削除したいファイル以外のファイルも含まれる場合は、削除したいファイルだけが削除されたコミットに書き換えられる。 git filter-repo --path <削除したいファイルのリポジトリルートからの相対ファイル名> --invert-paths 別の例として、ファイルの内容に対して、ある特定の文字列を別の文字列に書き換える場合は、まずリポジトリ外(でもディスクの同じパーティション内)に(書き換え前の文字列)==>(書き換え後の文字列)という内容のファイル(内容の例:password==>123456)を作って、以下を実行する。この場合は当然コミットの削除ではなく書き換えになる。ここでは../conv.txtを作ったとする。 git filter-repo --replace-text ../conv.txt もっと単に最新のコミットを削除する場合は以下を実行する。"--refs HEAD^..HEAD"は最新1つ前のコミットより新しく最新のコミットを含めそれより古いの意味(つまり、最新のコミットだけ、の意味)、"--path-glob '*' --invert-paths"は「すべてのファイルを削除する」の意味である。ちなみにgit clone直後、HEADが指すブランチはクローン元のリポジトリのそれと同じになっているので、クローン元リポジトリのHEADの最新コミットと同じコミットをクローン先で削除する場合はクローン後にブランチの切り替えを行う必要はない。 git filter-repo --refs HEAD^..HEAD --path-glob '*' --invert-paths git filter-repoを実行するとリモートのoriginの設定は削除される(この削除されたリモートのoriginはgit clone元なので古いリポジトリのディレクトリ)。新しく作業用のリポジトリとすべく古いリポジトリと同じリモートoriginの設定を以下で行う。 git remote add origin <古いリポジトリのプッシュ先URL> 古いリポジトリのプッシュ先は.git/configの[remote "origin"]セクション(名前が"origin"の場合)のurlに書かれている。もちろん、元々リモートなんてなかった場合にはこの作業は不要である。 この作業の前提は「リポジトリが自分が持つ1つしかないか、まだ削除したいコミットをプッシュしておらず自分のローカルにしかない場合」なので、後は仮のコミットとして退避してあった作業中のファイルがあればgit reset HEAD^等で戻してGitで行う作業は終了である。 後は古いリポジトリを削除して、必要なら新しいリポジトリのディレクトリ名をリネームする。 機密情報をディスクから完全に消したいなら、先程「../conv.txt」のようなファイルを作ったとしたらそれも削除して、新しいリポジトリを別のディスクかパーティションに持っていって、必要なら.gitignoreを編集して機密情報を書くようなファイルをgit管理外にし、古いリポジトリのあったディスクかパーティションをフォーマットするとかddで消去するとかいったディスク上の掃除を行うことになる。そこまでやりたくないって? まあそれはお好きにどうぞ。 削除したいコミットがすでにプッシュされている場合 問題はすでにプッシュしてあった場合である。プッシュ先のリポジトリが全世界に公開されたもので、そこに機密情報が含まれていたならすぐ気付いたとしてももう誰かに見られていると考えた方が良い。とりあえずGit周りの作業なんて後回しで可及的速やかにパスワードなら変更したりキーなら無効化したりしなければならない。 その後で、あるいは見られても問題はない情報か相手だったなら、そのリポジトリに対する作業者全員(少なくとも、消したい情報をすでにフェッチしてしまった全員)に残したい作業中のファイルを仮にコミットしてからローカルのコミットを全部プッシュしてもらい、そこでそのリポジトリに対する作業を中断してもらう。 修正したリポジトリを作業者全員に行き渡らせなければならないので、プッシュ先のリポジトリが修正されないとならない。プッシュ先がGithub等、こちらでリポジトリの中身を触ることができない場所ならサポートに連絡して対応を仰ぐことになる。 プッシュ先がこちらでリポジトリの中身を触ることができるなら2つのやり方がある。1つはローカルのリポジトリで上記「削除したいコミットがまだプッシュされていない場合」の対応をした後、コミット情報とタグ情報を以下でプッシュする。 git push origin --force --all git push origin --force --tags その次にプッシュ先のリポジトリでreflogの全削除を以下で行う。--expire=nowはgc.reflogExpire設定(デフォルト:90日以上前のものを削除する)を無視して現在より前のreflogを削除するオプション、--allはすべてのリファレンスに関するreflogを削除するオプションである。 git reflog expire --expire=now --all さらにコミットに紐付かなくなったファイル等も以下で削除する。--prune=nowはgc.pruneExpire設定(デフォルト:2週間以上前のものを削除する)を無視して現在より前のどこからも参照されていないオブジェクトを削除する。オブジェクトはコミット、ツリー、ブロブ(ツリーに含まれるファイル)、タグの補足情報(git tagの-aや-sや-uのオプション付きで作ったタグに付けられる)の総称である。 git gc --prune=now もう1つのやり方はプッシュ先のリポジトリで「削除したいコミットがまだプッシュされていない場合」の対応をすることである。ちなみにgit reflog expire --expire=now --allとgit gc --prune=nowはgit filter-repoが実行時に行う作業としてmanに書かれているものそのままなので、git filter-repoを実行したらこれらも実行されている。 プッシュ先のリポジトリをきれいにできたなら、その後で作業者全員にその修正を行き渡らせる。以下のようないくつかのやり方があるだろう。 手間が掛からないのはローカルリポジトリを削除して再度クローンして持ってくる方法である。手間は掛からないがリポジトリが大きいと時間は掛かる可能性がある。その後、git checkout <ブランチ名>で使うブランチを復帰させる。 既存のリポジトリを生かすなら、git fetch --allですべてのリモートブランチを、git fetch --tags -fですべてのタグをフェッチし、git branch --format='%(refname:short)' | xargs -i{} sh -c "git checkout -B {} origin/{} || git branch -D {}"でローカルブランチを強制的に作り直す(リモートにないブランチは削除する)。その後は例によってgit reflog expire --expire=now --allとgit gc --prune=nowを実行する。 プッシュしてないファイルがあるからそんなことしたくないという場合は、その作業者のリポジトリにもgit filter-repoをリモートの時と同じオプションで掛けてやる。その後、git remote add origin <元のプッシュ先URL>してからgit fetch --all等でフェッチ。 ここまででGitでの作業は終了である。後は「削除したいコミットがまだプッシュされていない場合」の古いリポジトリを削除して、以降と同じ作業となる。 なお、機密情報をプッシュしないように、という用途なら、git-secretsのようなコミットさせないようにするソリューションや、git-cryptのような自動で暗号化を行ってくれるようなソリューションの使用も検討すると良いだろう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【あるある】「やべ、コミットから抜けてるファイルがあった」の解決法

目的 gitでコミットして、そのまま作業を進めようと思った時に、「あ、この修正・追加もさっきのコミットに入れておけばよかったーー!!」ということがよく起きる。この時にすぐにその修正を最新のコミットに入れたいと考えた。 結論 記事にしていいのかと言うくらいすごい簡単だった。 ① 追加したいファイルをステージングし、 ② git commit --amend --no-editで前回のコミットにステージングされているファイルを適用させる。 詳細 追加したいファイルをステージング 前回のコミットに追加したいファイルをステージングする $ git add test.py 前回のコミットにステージングされているファイルを適用 $ git commit --amend --no-edit 参考 [Git] 追加の変更を最新のコミットに追加する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む