gitの使い方しくじり先生~こんな使い方はするな~
はじめに
はじめまして、yasuda_naoto と申します。
未経験から WEB エンジニアとして活躍するために RUNTEQ というプログラミングスクールで学習しています。
概要
RUNTEQ ではミニアプリ作成会というものがあり、2023 年の 8 月に青春をテーマにたくさんのアプリが投稿されました。
その際に、愚かな私は「面倒だからgit add .
してそれらを一気に commit
して push
すればええやろ」という、プログラマにあってはならないめんどくさがり精神で作ったアプリをリモートリポジトリに push
してしまったのです。
その際に起きた悲劇を再現します。
更に、同じ轍を踏まないように、それを防ぐ方法と、もしあなたが同じしくじりをしてしまったら、そこから立て直す方法をご紹介します。
要点
- 細かく add & commit しなかったばかりに push が途中で進まなくなっちゃった
- git reset というコマンドで変更を巻き戻したよ!
- 反省して add & commit をしたらうまくいったよ!
- このやり方の良くない点、次回から気をつけること
どんなしくじりをしたか
前提知識
まずはアプリケーションを作成してからリモートのリポジトリに push
するまでの過程をよくわからない方向けに解説します。
基本的には以下の手順で行います。
- git init を使って git の管理下にファイルを置く
- git add . ですべてのファイルをステージングさせる
- git commit でコミット
- github 上にリポジトリ作成
- git remote add origin {URL} で origin の github のブランチを作成
- git push origin main で origin の main ブランチに push
- git init:
git init を行うことで通常のリポジトリを git 上で管理することができるようになります
- git add:
add ではステージングという作業を行います。これは、次に行う commit という変更の保存の対象になるようにファイルを指定してやることです。
- git commit:
ここでステージングされているリポジトリを保存できます。変更をこまめにステージング(add)&commit することで、バグや不具合が見つかっても履歴を辿って以前の状態を復元しやすくなったり、コミットメッセージ(例:commit -m "xxxx")をつけることでどこをどのように変更したか見やすくなります。
- git remote add origin {URL}:
remote とはリモートリポジトリのことで、これはみんなが共有して使うリポジトリです。これは github 上にあるリポジトリで、開発の大元になっています。
反対にはローカルリポジトリがあり、これは大抵は VScode なり Vim なりで開発を行っている手元にある開発環境のことを指しています。origin とはリモートリポジトリのアクセス先です。
git remote -v
コマンドを利用すると origin がどのように設定されているかわかります。
origin https://github.com/nto300002/shikujiri.git (fetch)
origin https://github.com/nto300002/shikujiri.git (push)
{URL} の部分には github 上で作成したリポジトリの URL が入ります。
状況再現
まず最初に、次の画像を御覧ください。
こちらは React で作られたアプリの public というフォルダ(画像などをいれるフォルダ)です。流石にやりすぎだろというくらい盛っていますが、これによってアプリ全体の容量がものすごく大きくなっているということを感じていただきたいです。
次にこちらを御覧ください。
Github 上でリポジトリを新しく作成したときに出るコマンドをすべてコピペした状態です。
ここには、先程の大量の動画はおろか、React のアプリケーションすら存在していません。
みなさんはこの状態から
・git add .
・git commit
・git push
これらの一連の流れを行うとどうなってしまうか想像がつくでしょうか?
実際にやってみた
実際にこれを行うと
Enumerating objects: 33, done.
Counting objects: 100% (33/33), done.
Delta compression using up to 8 threads
Compressing objects: 100% (31/31), done.
Writing objects: 100% (32/32), 26.71 MiB | 324.00 KiB/s, done.
見た目上はなんとかなっているようですが、ここから先が全く進みませんでした。
何度やっても同じことの繰り返しになってしまうため、結局、次のような解決策を取りました。
どうやって解決した?
履歴を確認し過去に戻してみる
- 「git log」で履歴を確認する。
- 「git reset --hard 履歴の id 番号」を打ち、push する前の履歴に戻す
- 容量が大きいファイルを一つ一つこまめに add & commit する
- 再度「git push origin main」で github に push する
上記を一つ一つ解説します。
- 「git log」で履歴を確認する。
commit aa1c20508fa5f77709008f31147787f9717bcca9 (HEAD -> add_wavfile, origin/add_wavfile)
Author: nto300002 <samonkntd@gmail.com>
Date: Tue Oct 3 19:52:48 2023 +0900
add: wavfile
commit 7b77d51d7abe136bdd0bff562d1e136ae239e635 (origin/main, main)
Author: nto300002 <samonkntd@gmail.com>
Date: Tue Oct 3 19:49:30 2023 +0900
add: 画像追加
①commit aa1c20508fa5f77709008f31147787f9717bcca9 (HEAD -> add_wavfile, origin/add_wavfile)
この commit に続く暗号みたいな数字がコミット ID です。これを指定することにより、過去に行った変更を取り消すことができたりします。これを駆使して履歴を取り消すことができます。
(HEAD -> add_wavfile, origin/add_wavfile)
これは左がローカルでの作業ブランチで右が push したリモートリポジトリのブランチになります。HEAD
とは現在作業を行っているブランチのことを指しており、それが add_wavfile というブランチに切り替わったことを表しています。リモートリポジトリのブランチは基本origin/ブランチ名
となっていることを覚えておくといいでしょう。
②Author: nto300002 <samonkntd@gmail.com>
Author はそのブランチの編集者のことを指しています。ご丁寧に git に登録したメールアドレスまで表示されます。
③Date: Tue Oct 3 19:49:30 2023 +0900
言わずもがな、編集した日時です。
- 「git reset --hard コミット ID」を打ち、push する前の履歴に戻す
git reset とは、特定の時点までファイルの状態を巻き戻すことができます。
このオプションに
--soft、--mixed、--hard があります。
HEAD の位置・ステージ・作業ディレクトリを巻き戻すことができ、名前のとおり、左からちょっとづつ巻き戻す能力が強くなります。
- --soft
巻き戻す範囲:HEAD(今いるところ)
弱い。 - --mixed
巻き戻す範囲:HEAD, ステージ - --hard
巻き戻す範囲:HEAD, ステージ, 作業ディレクトリ
強い。
今回作業ディレクトリまで巻き戻しましたが、--mixed を使ってステージングまでを取り消すだけでよかったのかも。
3,4 は前提知識を参照
つまり何をしていたかというと、一旦 push した履歴を辿って巻き戻し、再度こまめに add & commit を行い push したということです。
さらに安全な方法
今回、たまたま見つけた記事でgit reset
を使う方法を見つけたのでそれを試しましたが、”巻き戻す”という性質上、一度巻き戻してしまうと復元が難しく、それ故 git 初心者には扱いづらいコマンドであるということが後にわかりました(新たなしくじり)。
そこでさらに安全な commit の取消方法と、上記のような問題を予防する git の使い方について教えます。
-
git revert
git reset
は履歴を巻き戻すものというのは上記で紹介したとおりですが、こちらのgit revert
は履歴を"打ち消す"ものだと思ってください。
git revert
の利点は、打ち消す用のコミットを追加しているだけなので、上記の図で revertA という commit を追加した場合、それを元の A という commit に戻したくなった場合でもすぐに戻せるということです。
git を使って後悔しないために
今後 WEB エンジニアになりたい人にとって、チーム開発は避けては通れず、また、ポートフォリオ上でもこまめに branch を切っているか、commit の粒度はどうかということまで見られる時代になってきたという話をよく耳にします。それほどまでに git の使い方が重要視される昨今、上記のようなしくじりを実務でも経験しないために、どうすればよいかを反省を踏まえてリストアップします。
- 変更に関連するものを add & commit する
- commit は細かく行う
- git status を見る
- git diff で差分の確認
- issue ドリブン開発
解説
-
git status
どのファイルがステージング(git add)されているか見ることができます。git status On branch add_wavfile Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working directory) deleted: public/11.jpg deleted: public/5min copy 2.wav modified: public/robots.txt Untracked files: (use "git add <file>..." to include in what will be committed) public/.jpg public/3 (5) copy 2.wav public/3 (5) copy.wav public/add.mp4 public/mod.wav
- Changes not staged for commit:
既存のファイルに変更が加えられているけれど、ステージングされていない状態
deleted:
削除されている
modified:
変更されている - Untracked files:
単にステージングされていないファイル
- Changes not staged for commit:
-
git diff
変更差分を見ることができます。
diff --git a/public/11.jpg b/public/11.jpg
deleted file mode 100644
index ad4e91b..0000000
Binary files a/public/11.jpg and /dev/null differ
diff --git a/public/5min copy 2.wav b/public/5min copy 2.wav
deleted file mode 100644
index b0ca089..0000000
Binary files a/public/5min copy 2.wav and /dev/null differ
diff --git a/public/robots.txt b/public/robots.txt
index e9e57dc..4e36859 100644
--- a/public/robots.txt
-
issue ドリブン開発
最初に作業を issue という単位にまとめておき、issue 毎に branch を切って作業する開発手法です。branch 毎に細かくタスクを割り振るので、今回のような失敗は防げる(branch の粒度にもよる)と思います。
issue を追加する ↓
例えば、上記のように issue を設定したあとは、自動で issue の番号が割り振られます(#24)。issue の番号が #24 ならばgit switch -c issue/24-BranchName
とするだけで自動で issue と branch が紐づいてくれます。
上記は一例で、他にも違うやり方で issue ドリブン開発を行っているチームもあると思いますので、実際に業務に入ったら、そのチーム特有の git の使い方(お作法)を学んだほうがよいでしょう。個人開発であれば、やりやすい方法で大丈夫だと思います。
まとめ
- git を使う際は、こまめに add & commit を行おう
- 自分が行った変更を確認してから push するようにしよう
- 業務に入ったら、開発の作法を確認しよう
終わりに
git は Ruby や JavaScript といったプログラミング言語に比べて、あまり華がなく、学習していてもその重要性に気づけない人も多いのではないかと思います。自分は重要性については理解しているものの、効果的な使い方をあまりよく理解せず使っていました。
これを見ている人にもきっと、add や commit,push しか使ったことがない人もいるのではないかと思いますが、この記事を見て git の奥深さに触れてもらえれば幸いです。
私も未熟者ですが、一緒に学習を頑張りましょう!
参考にした記事
git push した際の容量エラーに付いての記事
git reset
git revert
issue ドリブン開発
Discussion