0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

新卒がGitのコマンドを丸暗記するのをやめた話

0
Posted at

はじめに

はじめまして、新卒エンジニアのfuyunokiです。

配属されてから Git を毎日使うようになったのですが、addcommit の違いも、resetcheckout の違いも、正直なところ雰囲気で打っていました。コマンド集を見ても「そういうものだ」としか書いていないので、覚えられないし、応用も効きません。

そこで もう怖くないGit!(Udemy) を一通りやって、手を動かしながら整理し直しました。

そこで分かったのは、自分がコマンドを暗記しようとしていたのが、そもそも間違いだったということです。Git のコマンドは、たった4つの場所のあいだで何かを動かしているだけでした。

いま自分がどこにいるかが分かれば、コマンドは「覚えるもの」ではなく「選ぶもの」になる。

本記事は、その考え方を新卒の自分に向けて書き直したものです。

この記事について

  • 前提知識:git addgit commit を打ったことがあること。それ以外は説明します
  • 記事中のコマンドと出力は、すべて手元で実行して確認したものです(Git 2.50.0 / Windows)
  • 「記録する → やり直す → 分岐する → 共有する」という、実際に覚えていく順番で並べています。目次から必要なところに飛んでもらって構いません

第0章 Git の世界地図

ここだけは飛ばさずに読んでください。この章の図が頭に入っていれば、残りの章は「その図のどこを動かす話か」でしかありません。

4つの場所

Git を使うとき、あなたのファイルは4か所のどこかにいます。

実線が「前に進める」コマンド、点線が「戻す」コマンドです。

見てのとおり、よく使うコマンドはほぼ全部この図の矢印のどれかです。逆に言うと、新しいコマンドに出会ったときも「これはどこからどこへ動かすんだろう」と考えれば、だいたい当たりが付きます。

git statusgit diff は矢印ではなく、「いまファイルがどこにいるか」を教えてくれるコマンドです。迷子になったらこれを打ちます。

そしてもう一つ、この記事の全体を貫く原則を先に置いておきます。

④ リモートに出した履歴は、書き換えない。

④ に出した時点で、その履歴は自分だけのものではなくなります。この記事に出てくる注意書きは、ほぼ全部ここから導かれます。

コミットは「差分」ではなく「そのときの全体」

もう一つの誤解が、これでした。自分はコミットを「変更点のメモ」だと思っていましたが、違います。

コミットは、そのときのファイル全体の写真(スナップショット)です。そして、1つ前のコミットが誰なのかを覚えています。

矢印は「親」を指しています。時系列は左から右です。

コミットが数珠つなぎになっているので、一番新しいコミットさえ分かれば、そこから過去を全部たどれますgit log が履歴を一覧できるのは、この鎖をさかのぼっているからです。

「全体を保存したら容量が大変では」と思うところですが、Git は変わっていないファイルを使い回すので、実際にはそこまで膨らみません。

ブランチと HEAD は「付箋」

そして、自分が一番驚いたのがここです。

ブランチは、コミットに貼られた付箋にすぎません。フォルダのコピーでも、履歴の複製でもありません。「いま main の先頭はこのコミットですよ」と示しているだけの目印です。

そして HEAD は、「いま自分がどの付箋のところにいるか」を指すもう1枚の付箋です。

この図が頭に入ると、いろいろな挙動が一気に説明できます。

ブランチを切るとは、付箋をもう1枚貼ること。

git checkout -b feature がやったのは、付箋を1枚増やして、HEAD をそちらに向けただけです。ファイルは1バイトもコピーされていません。

ここから、よく言われるアドバイスの理由がそのまま出てきます。

迷ったら先にブランチを切る。

これが推奨されるのは「習慣として良いから」ではありません。コストがほぼゼロで、失敗しても元のコミットに付箋が残るからです。あとで出てくるリベースのような怖い操作の前に git branch backup と打っておけば、それだけで戻れます。

コミットするとは、付箋を前に進めること。新しいコミットを作ると、いまいるブランチの付箋がそちらへ移動します。だから作業していると main の先頭が自然に進んでいきます。

おまけ:detached HEAD の正体

新卒がよく踏むやつです。ブランチ名ではなくコミットを直接 checkout すると、こうなります。

$ git status
HEAD detached at 17b4320

HEAD がどのブランチの付箋も指していない状態。これが detached HEAD です。「切り離された」というのはそういう意味でした。

エラーではないので焦らなくて大丈夫です。この状態でコミットすると、そのコミットを指す付箋が誰もいないので迷子になりやすい、というだけです。戻るには、ブランチ名を指定して checkout し直します。

$ git checkout main

第0章のまとめ

覚えること ひとこと
4つの場所 ワークツリー → ステージ → ローカル → リモート
コミット そのときの全体の写真。親を1つ持つ
ブランチ コミットに貼った付箋。作るのはタダ
HEAD いま自分がいる場所を指す付箋

ここから先は、この4つの応用でしかありません。


第1章 記録する

この章でできるようになること:変更を意図どおりの粒度でコミットし、いま何がどこにいるかを確認できる。

リポジトリを用意する

# 新規作成(initialize の略)
git init

# 既存リポジトリの複製
git clone <リポジトリURL>

git init を実行すると .git/ という隠しディレクトリが作られます。履歴の実体はすべてここに入っています。プロジェクトのフォルダをコピーすると履歴ごとついてくるのはこのためで、逆に .git/ を消すと履歴も消えます。

変更を記録する

# ステージに追加(① → ②)
git add <ファイル名>
git add <ディレクトリ名>
git add .

# コミット(② → ③)
git commit
git commit -m "<メッセージ>"
git commit -v            # 差分を見ながらメッセージを書く

なぜ add と commit が分かれているのか

自分が最初に分からなかったのがこれでした。1コマンドでいいのでは、と思っていました。

分かれているのは、「何を一つの変更として記録するか」を自分で選ぶためです。ステージは、その選別のための予約席でした。

たとえばバグ修正のついでにコメントの誤字も直したとき、まとめてコミットすると、後から「バグ修正だけ取り消したい」と思っても巻き添えが出ます。ステージがあれば、関係あるファイルだけ add して先にコミットできます。

git commit -v は、メッセージを書くエディタに差分が一緒に表示されるオプションです。何を変更したか忘れた状態でメッセージを書くことが減るので、自分は普段こちらを使っています。

いまどこにいるかを確認する

git status               # 変更されたファイルの一覧

迷ったらこれです。「変更したがまだ add していないもの」と「add 済みのもの」が分けて表示されます。

git diff                 # add する前の変更
git diff <ファイル名>
git diff --staged        # add した後の変更

diff引数なしと --staged で、比べている対象が違います。ここも第0章の場所の話です。

┌──────────────┐        ┌────────────┐        ┌──────────────┐
│  ワークツリー │ ←───→  │   ステージ  │ ←───→  │  最新コミット │
└──────────────┘        └────────────┘        └──────────────┘
                git diff               git diff --staged

「変更したのに diff に何も出ない」というときは、たいてい既に add してしまっていて --staged のほうを見ていないだけです。自分はこれで何度か首をかしげました。

履歴を見る

git log
git log --oneline        # 1行表示
git log -p <ファイル名>   # ファイルの変更差分つき
git log -n <コミット数>   # 表示件数を制限

普段は --oneline で足ります。第0章のコミットの鎖を、新しいほうからさかのぼって表示しているだけです。

-p は「このファイルがいつ、どう変わったか」を追いたいときに使います。障害調査でよく使うことになります。

ファイルを消す・移動する

# ファイルごと削除
git rm <ファイル名>
git rm -r <ディレクトリ名>

# ファイルは残して、Git の管理からだけ外す
git rm --cached <ファイル名>

# 移動・リネーム
git mv <旧ファイル> <新ファイル>

git mv は、実は下記3つと等価です。普通のコマンドで代替できるので、無理に覚えなくて大丈夫です。

mv <旧ファイル> <新ファイル>
git rm <旧ファイル>
git add <新ファイル>

一方 git rm --cached は覚えておいたほうがいいコマンドです。「もう追跡したくないが、手元のファイルは消したくない」ときに使います。

.gitignore に書き足しただけでは、既にコミットされているファイルは管理から外れません。あとから「設定ファイルをうっかりコミットしていた」と気づいたときは、この操作が必要になります。

管理しないファイルを決める

.gitignore に書きます。対象は主に自動生成されるファイル(ビルド成果物、node_modules など)と、パスワードなどが書かれているファイルです。

# #から始まる行はコメント

# 指定したファイルを除外
index.html

# ルートディレクトリのものだけを指定
/root.html

# ディレクトリ以下をすべて除外
dir/

# 「/」以外の任意の文字列にマッチ
/*/*.css

第2章 やり直す

この章でできるようになること:やらかしたときに、どこまで戻すのかを自分で選べる。

自分にとって一番の鬼門がここでした。「戻す」コマンドが複数あって、毎回どれを打てばいいのか分からなかったからです。

整理すると、第0章の4つの場所のうち、どこまで戻すかが違うだけでした。

戻したい対象 コマンド 何が起きるか
① ワークツリーの編集 git checkout -- <ファイル名> 編集内容が消える
② ステージに載せた変更 git reset HEAD <ファイル名> ステージから下ろすだけ
③ 直前のコミット git commit --amend コミットが作り直される
# ワークツリーの編集を取り消す
git checkout -- <ファイル名>
git checkout -- .

# ステージから下ろす(ワークツリーはそのまま)
git reset HEAD <ファイル名>
git reset HEAD .

# 直前のコミットをやり直す
git commit --amend

名前に騙されないための3点

git reset HEAD は、編集内容を消しません。ステージから下ろすだけで、書いたコードはそのまま残ります。自分は「reset」という名前の強さから、編集ごと吹き飛ぶと思い込んでいました。実際に編集が消えるのは git checkout -- のほうです。

checkout-- には意味があります。checkout はブランチの切り替えにも使うコマンドなので、ブランチ名とファイル名が同じだと、Git がどちらを指しているか判断できません。-- はその区切りです。癖として常に付けておくと事故が減ります。

git commit --amend は push 済みのコミットに使ってはいけません。理由は次で説明します。

amend と「履歴を書き換えるな」の正体

「履歴を書き換える」と言われますが、実際には書き換えていません。作り直しています。

$ git rev-parse HEAD        # いまのコミットを確認
82f5dc22724c8405943737e39b330565bc41587b

$ git commit --amend -m "メッセージを直した"

$ git rev-parse HEAD
09ff3eb092aeaf4944f5e36763303b1b24f783bf   # ← 別のコミットになっている

起きたことを図にするとこうです。

元のコミットが書き換わったのではなく、別のコミットが新しく作られて、main の付箋がそちらへ移っただけです。

さて、ここで他の人が元のコミットを既に pull していたらどうなるでしょうか。相手の手元の付箋は古いコミットを指したまま、こちらは新しいコミット。同じ変更を表すコミットが2つ存在することになり、どちらが正しいのか機械には決められません。

これが「共有した履歴は書き換えるな」の中身です。マナーの問題ではなく、付箋の指す先が食い違うという事故でした。後で出てくる rebase も同じ理由で危険です。

reset の3つのモード

--soft / --mixed / --hard は暗記対象にされがちですが、どの場所まで巻き込むかが違うだけです。実際に3つとも試すと、こうなります。

                HEAD        ステージ      ワークツリー
                 │            │              │
--soft     ◄─────┤            │              │
--mixed    ◄─────┴────────────┤              │
--hard     ◄─────┴────────────┴──────────────┤  ← 編集内容が消える

v1 をコミット → v2 をコミットした状態から、HEAD~(1つ前)へ戻してみた結果です。

$ git reset --soft HEAD~
$ git status --short
M  f.txt          # ← 左の桁 = ステージ。v2 がステージに載ったまま
$ cat f.txt
v2

$ git reset --mixed HEAD~   # オプションを付けないときの既定
$ git status --short
 M f.txt          # ← 右の桁 = ワークツリー。ステージからは下りた
$ cat f.txt
v2

$ git reset --hard HEAD~
$ git status --short
                  # ← 何も出ない
$ cat f.txt
v1                # ← 編集内容が消えた

編集内容が実際に消えるのは --hard だけです。これが唯一「取り返しがつきにくい」モードなので、打つ前に一呼吸置いてください。

ちなみに日常でよく使う git reset HEAD <ファイル名>(ステージから下ろす)は --mixed なので、ワークツリーには影響しません。

最後の保険:reflog

git reflog は、HEAD がこれまでどのコミットにいたかの移動ログです。

$ git reflog
09ff3eb HEAD@{0}: commit (amend): メッセージを直した
82f5dc2 HEAD@{1}: commit: ログイン画面を追加
17b4320 HEAD@{2}: commit: READMEを修正
ef3b00f HEAD@{3}: commit (initial): 最初のコミット

さっき「誰も指していない」と書いた 82f5dc2 が、ちゃんと残っています。だから戻せます。

git reflog                     # 移動履歴からハッシュを探す
git reset --hard <ハッシュ>     # そこへ戻す

「Git は大体なんとかなる」と言われるのは、この仕組みがあるからです。ただし救えるのは一度コミットしたものだけで、コミットしていない編集は戻せません

教訓:危ないことをする前に、雑でもいいからコミットしておく。あるいはブランチを切っておく。どちらもタダです。


第3章 分岐する

この章でできるようになること:作業ごとにブランチを切り、コンフリクトが出ても慌てない。

ブランチのコマンド

# 作成(切り替えは行わない)
git branch <ブランチ名>

# 一覧
git branch
git branch -a            # リモートのものも含めてすべて

# 切り替え
git checkout <既存ブランチ名>
git checkout -b <新ブランチ名>   # 作成と切り替えを同時に

# 名前の変更(作業中のブランチが対象)
git branch -m <新ブランチ名>

# 削除
git branch -d <ブランチ名>       # 未マージなら削除しない
git branch -D <ブランチ名>       # 強制削除

git branch は付箋を貼るだけで、HEAD は動かしません。実際にはほぼ毎回セットで使うので、git checkout -b のほうを覚えておけば足ります。

-d と -D ── 安全側と強制側

削除の -d-D の違いは、Git 全体に共通する設計思想の典型です。

-d は、まだマージされていない変更が残っている場合、削除を拒否します。

$ git branch -d feature
error: The branch 'feature' is not fully merged.

これは「うるさいな」ではなく、「まだ取り込まれていない作業がありますよ」という警告です。普段は -d を使い、拒否されたら理由を考える。本当に捨てていいと確信したときだけ -D にする。

Git はこの手の「安全側と強制側」を対で用意しています(checkout --reset HEAD もそうでした)。普段は安全側を使っておけば、大きな事故は起きません。

マージする

git merge <ブランチ名>
git merge <リモート名>/<ブランチ名>

マージすると、親を2つ持つコミット(マージコミット)が作られます。これが「履歴に分岐の跡が残る」ことの正体です。

  main      A ─── B ─── D ─────────── M     ← M は親を2つ持つ
                   \                 /
  feature           C ─────────────/

なお、分岐していない場合(main が進んでいない場合)は、付箋を前にずらすだけで済みます。これが fast-forward と呼ばれるものです。

コンフリクト

CONFLICT (content): Merge conflict in <ファイル名>

初めて見たときはドキッとしますが、コンフリクトは異常ではありません。「同じ場所を二人が別々に変えました」という事実の報告です。どちらが正しいかは機械には決められないので、人間が決めてください、というだけの手続きです。

手順はこうなります。

  1. 該当ファイルを開く
  2. 衝突している箇所を確認する
  3. どちらの変更を採るか(あるいは両方を活かすか)を決め、手動で修正する
  4. 解決した内容をコミットしてマージを完了する

ファイルを開くと、こういうマーカーが入っています。

<<<<<<< HEAD
自分の変更
=======
相手の変更
>>>>>>> feature

<<<<<<< から ======= までが自分側、======= から >>>>>>> までが相手側です。**マーカーの行ごと消して、正しい状態に書き直します。**消し忘れるとそのままコミットされてしまうので、そこだけ注意してください。


第4章 共有する

この章でできるようになること:チームのリポジトリと安全にやり取りし、プルリクエストで開発を回せる。

リモートを登録する

# 登録されているリモートを見る
git remote
git remote -v            # 対応する URL つき

# リモートを登録する
git remote add <リモート名> <リモートURL>

# 送信する
git push <リモート名> <ブランチ名>

# 詳細情報
git remote show <リモート名>

# 変更・削除
git remote rename <旧リモート名> <新リモート名>
git remote rm <リモート名>

小さいことですが、origin は Git の予約語ではありません。慣習的に使われているショートカット名にすぎません。git remote add は要するに「長い URL に短い名前を付ける」操作です。

fetch と pull の違い

つまり、こういう関係です。

# pull は下記 2 つと等価
git fetch origin main
git merge origin/main

pull = fetch + merge

fetch はリモートの内容を持ってくるだけで、作業中のブランチには手を触れません。「中身を確認してから取り込みたい」ときは fetch、「確認せずそのまま取り込んでいい」ときは pull。この使い分けになります。

自分は最初、全部 pull で済ませていましたが、大きな変更が来ているときは fetch してから git log origin/main で中身を見るようにしています。

プルリクエストの流れ

チームで回すときの標準手順です。作業を始める前に main を最新にするのが起点になります。

  1. ローカルの main(master)を最新にする
  2. 作業用のブランチを切る
  3. 修正し、コミットする
  4. ブランチをリモートにプッシュする
  5. プルリクエストを作成し、レビューを依頼する
  6. レビューを受けて修正し、再度レビューを依頼する(承認まで繰り返す)
  7. 承認されたらマージする
  8. 不要になったブランチを削除する

1番を飛ばすと、あとで確実に痛い目を見ます。古い状態から作業を始めると、その分だけコンフリクトが増えるからです。自分はここを何度か雑にやって、余計な解決作業を増やしました。


第5章 履歴を整える(リベース)

この章でできるようになること:リベースが何をしているか理解したうえで、使っていい場面かどうかを判断できる。

ここからは少し上級です。便利ですが、使う場所を間違えるとチームに迷惑がかかります。

リベースとは何をしているのか

# ブランチの基点となるコミットを、別のコミットに移動する
git rebase <ブランチ名>

# pull をリベース型で行う
git pull --rebase <リモート名> <ブランチ名>

名前から「コミットを移動している」と思いがちですが、違います。別の場所に、同じ変更内容のコミットを作り直しています。第2章の amend と同じ理屈で、作り直したコミットは別物になります。

【マージ型】 分岐した事実が残る

  main      A ─── B ─── D ─────────── M     ← マージコミットが増える
                   \                 /
  feature           C ─────────────/


【リベース型】 一直線になる

  before    A ─── B ─── D           ← main
                   \
                    C               ← feature

  after     A ─── B ─── D ─── C'    ← C は C' として作り直される(別のコミット)

どちらを使うか

マージ型(既定) リベース型(--rebase
マージコミット 残る 残らない
履歴の形 分岐が図に残る 一直線になる
向いている場面 複数人が作業したブランチを統合する リモートの最新を取り込むだけ
弱点 履歴が複雑になる 作り直すので共有済みだと事故る

判断基準を一言にすると、「取り込むだけ」の pull はリベース型が向いている、になります。自分は何もしていないのに Merge branch 'main' of ... というコミットだけが積み上がるのを防げるからです。

一方、複数人が作業したブランチを統合するときは、分岐したという事実自体が情報なので、マージ型のほうが素直だと思います。

毎回 --rebase を付けるのを忘れるので、設定してしまうのが確実です。

# すべてのプロジェクトで pull をリベース型にする
git config --global pull.rebase true

リベースの3つの鉄則

  1. 公開済みのコミットをリベースしない。理由は第2章の amend と同じで、コミットが作り直されて他の人の付箋と食い違います
  2. 複数人が触っているブランチでは慎重に。コンフリクトが起きる確率が跳ね上がります
  3. 実行前にブランチを切っておく。付箋を1枚増やすだけのコストで、失敗しても元に戻れます

対話的リベース

複数のコミットをまとめて作り直す機能です。「コミットメッセージを直したい」「細かすぎるコミットを1つにまとめたい」というときに使います。

git rebase -i <コミットID>
git rebase -i HEAD~3         # 直近3コミットが対象

-i--interactive の略です。実行するとエディタが開き、対象のコミットが並びます。表示は古い順で、git log とは逆なので注意してください。

pick gh21f6d ヘッダー修正
pick 193054e ファイル追加
pick 84gha0d README修正

この行を書き換えることで、履歴を作り直せます。

まとめる —— squash を指定すると、そのコミットが直前のコミットと一つになります。一番よく使うのがこれです。

pick   gh21f6d ヘッダー修正
squash 193054e ファイル追加
squash 84gha0d README修正

並び替える・削除する —— 行を入れ替える、行ごと消します。

pick 193054e ファイル追加
pick gh21f6d ヘッダー修正

コミットをやり直す —— 対象を edit にします。

# edit gh21f6d ヘッダー修正
git commit --amend
git rebase --continue    # 次のコミットへ進む

分割する —— edit にして、リセットしてから細かくコミットし直します。

# edit 84gha0d READMEとindex修正
git reset HEAD^
git add README
git commit -m 'README修正'
git add index.html
git commit -m 'index.html修正'
git rebase --continue

対話的リベースは、並んだコミットをまとめて作り直す操作です。当然すべて別のコミットになるので、自分の手元にしかないコミットに対して使うのが前提になります。


第6章 道具箱

この章でできるようになること:知っていると地味に助かる機能を、必要なときに思い出せる。

スタッシュ(作業の一時避難)

別の作業に移りたいが、いまの変更は捨てたくないし、中途半端にコミットもしたくないときに使います。「急ぎのバグ対応を頼まれた」場面の定番です。

# 避難する(stash は「隠す」の意)
git stash

# 避難した作業の一覧
git stash list

# 復元する
git stash apply                  # 最新のものを復元
git stash apply --index          # ステージの状態も復元する
git stash apply stash@{1}        # 特定のものを復元

# 削除する
git stash drop                   # 最新のものを削除
git stash clear                  # 全部削除

stash@{0} が最新で、番号が大きいほど古いものです。

注意点として、apply は復元しても退避したものを消しません。要らなくなったら drop しないと、git stash list が過去の残骸で埋まっていきます。

タグ

リリース時点に目印を付けるための機能です。

# 一覧
git tag
git tag -l "v1.*"        # パターン指定

# 注釈付きタグ(名前・コメント・作成者・日時を持てる)
git tag -a <タグ名> -m "<メッセージ>"

# 軽量版タグ(名前だけ)
git tag <タグ名>
git tag <タグ名> <コミット名>   # 後からタグ付けする

# リモートに送る
git push <リモート名> <タグ名>
git push origin --tags   # ローカルにあってリモートに無いタグを一斉送信

ブランチとの違いは、第0章の付箋の話で説明できます。

        C1 ─── C2 ─── C3 ─── C4 ─── C5
         ▲                           ▲
       v1.0                        main

    打った場所に               コミットのたびに
     留まり続ける                 進んでいく

ブランチの付箋は新しいコミットのたびに前へ移動しますが、タグの付箋は動きません。「あのときここだった」を後から言うための道具です。

もう一つ、タグは push してもデフォルトでは送られません。明示的に送る必要があります。ここは忘れがちです。

コマンドに別名を付ける

毎日打つものは短くしておくと楽です。

git config --global alias.ci commit
git config --global alias.st status
git config --global alias.br branch
git config --global alias.co checkout

設定は階層になっていて、リポジトリ固有のもののほうが優先されます

範囲 場所
PC 全体(--global ~/.gitconfig
そのリポジトリだけ <project>/.git/config

チームの決まりごとはリポジトリ側、自分の好みは --global 側、という分け方になります。


おわりに

長くなったので、最後に持ち帰ってほしいものを3つだけ書きます。

1. コマンドではなく「場所」を覚える。
ワークツリー → ステージ → ローカル → リモート。どのコマンドも、この4つのあいだで何かを動かしているだけです。知らないコマンドに出会っても「どこからどこへ動かすんだろう」と考えれば当たりが付きます。

2. リモートに出した履歴は書き換えない。
amendrebase も、コミットを作り直して付箋を貼り替える操作です。共有済みのものでやると、他の人の付箋と食い違います。この一線さえ守れば、大きな事故は起きません。

3. 迷ったらブランチを切る。
ブランチは付箋を1枚貼るだけで、コストはほぼゼロです。怖い操作をする前に git branch backup と打っておけば、それだけで戻れます。

Git のコマンドは数が多くて覚えきれないと思っていましたが、場所と付箋という2つのモデルを持っただけで、大半は推測が効くようになりました。丸暗記しようとしていたのが、そもそもの間違いだったようです。

同じように「毎日 Git は使っているけど、意味は分かっていない」となっている方の助けになれば嬉しいです。

参考

何か訂正点あればコメントいただけると助かります。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?