「Oh shit, git!」を簡単に和訳してみた。(追記あり)

翻訳元: Oh shit, git!

gitは使いにくい!

Gitは難しい: 中身を破壊にするのは簡単なのに、過去の過ちを修正する方法を見つけるのは極めて困難だ。ドキュメントには修正するコマンド名が書かれていても、その名前を知らなければ使いものにならない。これは「鶏が先か、卵が先か」というジレンマを抱えている!

だから私が陥った数々の問題をいかにして抜け出すかを書いた。


なんて事だ!私は大変な誤ちを犯した!タイムマシンを呼び出すにはどうすればいい!?


git reflog
# you will see a list of every thing you've done in git, across all branches!
# each one has an index HEAD@{index}
# find the one before you broke everything
git reset HEAD@{index}
# magic time machine

reflog を使うと「誤って削除してしたコミット」や「壊れてしまったリポジトリ」、「失敗したマージ」などから正常な状態に回復させる事ができる。
このコマンド名は誰もが知っておくべきだ!

なんて事だ!前のコミットに小さなミスがあった!修正するにはどうすればいい?


# make your change
git add . # or add individual files
git commit --amend
# follow prompts to change or keep the commit message
# now your last commit contains that change!

ソフトウェアテストや文法チェックを行う際に、半角スペースを入れ忘れてしまいファールになってしまった。
あなたは新しいコミットで修正してから rebase -i を使ってミスを無かった事にできるが、こちらの方が数万倍高速だ。

なんて事だ!最新コミットのメッセージを間違えてしまった!


git commit --amend
# follow prompts to change the commit message

この愚かなミスを修正するにはこのコマンドを使え。メッセージを修正可能だ。

なんて事だ!新しいブランチを作ってコミットしたはずだが、誤ってmasterブランチにコミットしてしまった!


# create a new branch from the current state of master
git branch some-new-branch-name
# remove the commit from the master branch
git reset HEAD~ --hard
git checkout some-new-branch-name
# your commit lives in this branch now :)

:warning: すでにoriginへpushしてしまった場合はこの方法は使えない。その場合は git reset HEAD@{number} を使って元に戻すしかない。残念ながら、これは仕様だ。

なんて事だ!コミットを違うブランチに誤って追加してしまった!


# undo the last commit, but leave the changes available
git reset HEAD~ --soft
git stash
# move to the correct branch
git checkout name-of-the-correct-branch
git stash pop
git add . # or add individual files
git commit -m "your message here"
# now your changes are on the correct branch

多くの人がこのような状況に陥った場合はcherry-pickを使用することを提案している。あなたに合った方法で使い分けるべきだ。


git checkout name-of-the-correct-branch
# grab the last commit to master
git cherry-pick master
# delete it from master
git checkout master
git reset HEAD~ --hard

なんて事だ!diffを実行しても何も起こらないじゃないか!おかしくなったのか!?


git diff --staged

Gitはステージング状態(ファイルを追跡対象として追加した時)でdiffは行いません。これは仕様です。
(あなたはびっくりするかもしれませんが、慌てる必要はありません。)

もうダメだ。最初からやり直したい。


cd ..
sudo rm -r fucking-git-repo-dir
git clone https://some.github.url/fucking-git-repo-dir.git
cd fucking-git-repo-dir

Thanks to @viaz66 for this one.


:pushpin: ここから追記。

なんて事だ!最新コミットのメッセージを間違えてしまった!


git commit --amend -m "message"
# not use editor to change the commit message

-m オプションを使うと、いちいちエディタを開かなくても短いメッセージなら変更可能だ。
「Fix: Typo」 と打つだけにエディタを立ち上げるなんてバカバカしい事をするべきではない。

なんて事だ!最新より前のコミットが間違っていやがる!修正する方法はないのか!?


git commit --fixup HEAD~
git rebase -i HEAD~3

--fixup オプションを使うと、rebase時に修正コミットを当該コミットの位置へ自動的に移動させてくれる。
何も加工しないでエディタを閉じても誤ったコミットを叩き潰して修正する事が可能だ。
:warning: すでにoriginへpushしてしまった場合はこの方法は使えない。諦めて修正コミットを送るべきだ。

なんて事だ!気づけばリモートからめちゃくちゃ離れていやがる!手っ取り早く最新コミットまで追いかける方法はないのか!?


git fetch --all (or master)
git reset --hard origin/master

fetch コマンドに --all オプションを付けると「リモートにある全ブランチ」の最新情報を取得できる。
(すべて取得する必要がなければブランチ名だけでも問題はない)
自らの変更点を捨ててまで最新のコミットを追いたいなら --hard オプションをつけてリセットすれば良い。
それ以外ならmergeを使って整合性を取るしかない。(ただし、進みが早いブランチなら大変な苦労する事になるだろう。)

なんて事だ!一人で使っているリモートリポジトリなのに「non-fast-forward」と出てきてpushできない!何とかできないのか!?


git -f <command>

「フォースを使え、ルーク。使うんだ、ルーク。」
:warning: 複数人で共有しているリモートリポジトリでフォースを使うと全員ダークサイドに堕ちるので使うべきではない。