Help us understand the problem. What is going on with this article?

自分、何のGitコマンドやったか分かっとんのか...?

※この記事は 今年イチ!お勧めしたいテクニック by ゆめみ feat.やめ太郎 Advent Calendar 2019年12月10日(10日目)の記事です。

初めましての方は、はじめまして
ご存知の方は、そうだよ。ヒズミさんだよ。

縁とノリと勢いで、10日目を担当します。
僕は、俗物なので、ハマーンミュラーの椅子はきっと無理です(typoじゃないです)

epic1:悲劇は突然に

自分が何やったかわかっとんのか・・・( 'ω')👉
わ゙がっ゙どん゙の゙があ゙あ゙あ゙!? ( ‘ᾥ’ )👉👉👉

上キー押せよ・・・( 'ω')👉
う゛え゛キ゛ー゛お゛せ゛よ゛お゛お゛お゛お゛お゛お゛お゛お゛お゛お゛お゛!? ( ‘ᾥ’ )👉👉👉👉

 _人人人人人人人人人人人人_
>  $ git push -f origin master  <
  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄

explosions.png

epic2: git push -f origin masterって?なんで危ないの?

Linuxの禁忌コマンド rm -rf /と同じように扱われるgit push -f origin master なんかやっちゃダメという雰囲気はわかるけど、なんでダメなんだろう?ネットや先輩から聞いてそう思ったことないですか?

一言で言うなら、このコマンドでリポジトリを破壊することも可能です。
今までのリポジトリへの積み重ねを無に返すことが可能です。

その理由を、説明していきます。

そのGitコマンド、意味分かってます?

いつも叩いているGitコマンド。
その意味を理解して、入れているっけ?
僕はまだ分からないコマンドがいっぱいです。

変更ファイルをステージングに追加する。
git add
ステージングしたファイルをインデックスに登録する。
git commit

別の人の変更を取り込むために、
git pullまたはgit fetch/git mergeを、使ったりしますね。

それで、git pushは、リモートリポジトリにコミットを送るコマンドですね。

じゃあ、その先の"origin"って、何でしょうね。(-fについては後述)

originとは何者か

結論から先にいうと、Gitのpush.defaultの設定によっては入力したことない人もいると思いますが"origin"は、リポジトリのURLに対するエイリアス(ショートカット)です。

gitのpush.defaultについては、こちらを参照ください↓
gitのpush.defaultに関するノウハウ

自分のリポジトリのconfigを開いてみてください。
image.png
こんな記述があると思います。
これが、originの正体です。

epic3:"F"の意味は

"-f"についてです。(--forceでも、同じ動作になります)
pushに、"-f"または”--force”のオプションをつけるとリモートのコミットを無視して、要求されたオブジェクトでリポジトリを上書きします。(歴史は勝者が作ります。この場合の勝者は、force pushをした人を指します。)

SFもので言うところの”歴史改変”です。食らえライダー!歴史改変ビーム!!
あったことをなかったことにしてしまいます。
毎年どこで、force pushが危険だと言われるのはここにあります。

epic4:失われた過去を求めて

ここまで、危ない危ないといってきました。
でも実は、force pushしたリポジトリを戻すことも可能です。

方法はいくつかあって。

  • 他の人がforce pushする。 一番単純で、楽な解決方法。 素直にごめんなさいして、ボコられた後にforce pushしてもらいましょう。
  • reflogでハッシュ値を調べて、git resetで戻す。
    改変された歴史は繋がりがなくなっただけで、実際は残っています。
    reflogは、リポジトリに行われた操作を記録しています。
    無論、戻すべきコミットへのハッシュ値も記録されているので、これを元に改変された歴史をもとに戻すことができます。
    ここでは、説明は省きますが、reset --hardで消してしまったコミットも歴史に戻することが可能です。 具体的な方法は、こちらが参考になります。
    git reflog についてまとめてみる
  • ジ○ウがアナザーライダーを倒す

ここで、「なんだ、うっかりやっても大丈夫か。こっそり元に戻せる。」と、お思いでしょう。

ところがドッコイ

GitHubでは、これをユーザーからやることができません。
GitHub社に頼んで、reflogの内容を教えてもらうしか方法がないのです。
Jenkinsの開発者、間違えて一ヶ月前のローカルリポジトリをgit push --forceしてしまう
(しかも、ガーベジコレクションで掃除されてしまうと、もう手の打ちようがなくなる)

epic4:参考URL

epic5:まとめ

なんで、git push -f origin masterが、危険なのか
それは、origin(リモートリポジトリ)の歴史がローカルの歴史で上書きされてしまうから。
それにより他の人の成果物がなかったことにされてしまうからです。

これらを防止する方法がローカルのGit・リモートのGitHubの両方に用意されています。
origin/masterへのPush禁止やGit Hookでローカルの段階からmasterへのcommitを制限するなどなど。方法については、ご自身でググってみてください。

では、良きGitライフを送れますように。

epicEx:おまけ

ここまで、散々悪者扱いしてきましたが、force pushを使うユースケースは存在します。

  • Push済みのコミットメッセージの修正
  • AuthorやCommitrerの修正

あとは、epic4でも記述しましたが、誤った歴史の修正をするときにも、force pushを使います。

force push = 悪ではなく、その挙動を理解して、適切なタイミングで使えば、あなたの力になってくれます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away