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

Git就活筆記試験対策道場

image.png
photo by Jennifer Duda

はじめに

ちょっと前に面白いことに気がついた。開発に携わる友人たちの多くがGitというツールの重要性はよくよく分かっているのに、それが一体どういうツールなのかを時間をかけて分かろうとはしていないということだ。とは言っても、プログラマーとしてのサバイバルスキル的な観点から言えば、Gitは例えば演算法やデータ構造、他のプログラミング言語やフレームワーク開発のように深入りして学ぶ必要はなく、多くの人が日常的に必要なGitの操作といえばaddcommitpushpull、それに加えてブランチを切ることとマージが出来さえすれば十分といったところだろう。そういうこともあって、求人中の会社にとってGitを使えるというアピールポイントは採用を決めるにあたって「少しプラスに加味される条件」に過ぎず、使えないとかよく知らないからといって、すぐさま採用に影響があるとは言えないところだ。

うん…確かに今のところ職場でのGitの立ち位置というのはそんな感じだ。そんなわけだから、GitをFTP代わりに使うのもあながち間違っているとは言い切れない。…言い切れないのだが、だがしかし!開発に携わる、とりわけチーム開発に携わる人間にとっては、不正確な使用法は時折ファイルに予期せぬ混乱と喪失を招き、しかもチームのメンバーにも多大なる迷惑をかけかねない。

というわけで、自分が面接官だったら面接者に聞きたいなという採用試験の例題を幾つか用意してみた。この例題は「私Git使えます!」という開発者であれば、たぶん…たぶん問題なく答えられるのではないかと思うので、是非採用試験前の参考にしてみてほしい。もし、採用試験時にここに用意した例題以外でも面白い問題があったという人がいたら、是非下のコメント欄に報告をお願いします。

免責事項:

  1. これはどこかの企業の面接試験の過去問とかいった類のものではありませんので、就職及び転職活動にあたっては各自しっかりと準備をして下さい。試験に全く違うことが出て、結果不採用であったとしても責任は負いかねます。
  2. もし万が一台湾の弊社5xRubyの求人に応募して頂いたとしても、これらの問題が出るとは限りません。

用語問題

問題:
git push origin masterこのコマンドは一体何をするものか?

このコマンドは手もとのmasterブランチの内容を、(GitHubや、GitLabもしくは会社内部のGitサーバ内にある)originにpushし、かつorigin内に同名のmasterブランチを作成するものだ。

ただし、多くの人が完全なpushコマンドはこのようになることを知らない:

$ git push origin master:master

上のコマンドは「ローカルのmasterブランチの内容をoriginにpushし、しかもorigin上にmasterブランチを作成する」という意味なので、もしこのコマンドを以下のようにすると:

$ git push origin master:cat

これは「ローカルのmasterブランチの内容をoriginにpushし、origin上にcatブランチを作成する」という意味になる。


問題:
git clonegit fetchgit pullこの3つのコマンドの違いを説明しなさい。

git clone
cloneコマンドはネット上のプロジェクトを「丸ごと」手元のPCにコピーしてきて、尚且つPC内に同名のディレクトリを作成(.gitディレクトリを含む)するもの。通常このコマンドは一番初めに使うのみで、clone後にプロジェクトを更新したいのであれば、git fetch もしくはgit pullコマンドを使う。

git fetch
例えばoriginという名のリモートからgit fetchコマンドを実行したとすると、Gitはローカルとリモート(ここでいうorigin)のプロジェクトを比較して「origin上にはあるのにローカルにはまだない」内容をダウンロードしてくれる上に、ローカルに相応のブランチを作成してくれる。ただし、fetchコマンドはダウンロードしてくれるだけで、マージはしてくれない。

git pull
pullコマンドは、実はやることはfetchと変わらない。違いはfetchが単にプロジェクトをダウンロードしてくれるのに対して、pullはダウンロードしてくるだけではなくマージまでしてくれる。つまりgit pullというのはgit fetchgit mergeコマンドを加えたものだという言い方をすることが出来る。


問題:
GitにおけるHEADとは一体何か?

HEADというのは本質的には一つのタグに過ぎず、通常特定のローカル上のブランチやコミットを指している。なので、HEADは今いるブランチ(current branch)を指すものと考えてもらって構わない。


問題:
マージ後のブランチは通常どのように処理するのが適切か?また、それは何故か?

ブランチというのは、本質的には40桁のファイルに過ぎず、ブランチやファイルまたはコミットを削除したからといって消えるものではない。なので、マージ後のブランチを削除しようが、記念にとっておこうが実はどちらでも構わない。逆に言えば、取っておいたとしてもたかだが40Bytesの空間を占領するだけのことなので、数十、数百ギガの動画ファイルなんかと比べれば…というわけだ。


問題:
マージ済のブランチを削除してしまうと何が起こる?

ブランチというのは実はタグや付箋のようなものに過ぎず、特定のコミットの上に貼られているだけに過ぎない。つまりブランチはディレクトリやファイルといった類のものではない(確かに幾つかのバージョン管理システムではそういう形式をとるものも存在する)。Gitでは、削除されたブランチというのはちょうど、箱の上に貼られたシールを剥がすようなもので、シールを剥がしてしまったからといって箱自体に影響があるわけではない。つまり、マージ済のブランチを削除してしまったからといってどうってことはなく、ファイルやディレクトリまでが消えてしまうというような事態は起こらない。


問題:
git diffこのコマンドは一体どんな時に使うものか?

このコマンドは2つのコミット間の差異を比較したい時に使用する。例えば:

$ git diff e37078e d4d8d9d

こうすると、e37078ed4d8d9dという2つのコミットの違いを比べることが出来る。もしコマンドの後にSHA1ハッシュ値を1つしかのせなかった場合は:

$ git diff e37078e

e37078eと現在のHEADが指すコミットの違いを比較してくれる。それでは、もし全くSHA1ハッシュ値をつけなかった場合どうなるかというと:

$ git diff

Gitは「ワーキングディレクトリ」と「ステージングエリア」の違いを比較してくれる。つまり、git addを実行する前にこのコマンドを実行すれば、自分がどこを修正したのかを確認出来るのだ。もしgit addを既に実行して修正をステージングエリアに追加してしまっている場合は、--cachedオプションをつけると:

$ git diff --cached

現在のステージングエリアとHEADが指すコミットの違いを比較してくれる。


問題:
Gitを使用する際、通常どのようにタグを使っているか答えなさい。

通常はソフトウェア開発などでマイルストーンとして使ったりする。例えばソフトウェアのバージョン1.0.0とかbeta、releaseといった具合だ。こういう時にタグは非常に使いやすい。例えば:

$ git tag 1.0.0

こうするとあるコミット上に1.0.0というタグをつけることが出来る。


問題:
GitHub上にforkという機能があるが、このforkとgit branchコマンドの違いは何か?

GitHubのfork機能というのは「プロジェクトを丸々指定したアカウントにコピーしてくる」というもので、fork を実行するとGitHub上の表示はこのようになる:

Forkを実行後、修正箇所をコミットした上でPull Request(PR)を送ると原作者と交流を持ちながら、原案プロジェクトに自分のコミットで貢献をすることが出来る。

対してgit branchというのは、プロジェクト内に一つブランチを切って、そこで修正作業をし、作業終了後はgit mergeもしくはgit rebaseコマンドで修正点を合流させるというもの。


問題:
一般的なマージとrebaseを使った合流方式の違いは何か?またそれぞれのメリット、デメリットをあげよ。

一般的なマージというのは、基本的に(Fast Forward方式以外で)新しくコミットを作り出してそこで2つのブランチを合流させるものをいう。それに対してrebaseというのは、一般的なマージと違って新しいコミットを作り出したりしないという点に違いがある。

とは言っても、最後の結果だけを見れば、ファイルの内容からしても両者に違いは無いのだが、ログには明らかな違いが出てくる。つまり、誰が誰をrebaseしたかがログにはしっかりと記録として残されるのだ。例えばcatブランチがdogブランチ上にrebaseされた場合、catブランチはdogブランチの後ろに表示がくる。反対にdogブランチがcatブランチ上にrebaseされた場合dogブランチはcatブランチの後ろに表示される。

Rebaseを使うメリットは、合流するのにコミットを作り出したりはしないので幾分かログがすっきりと見えること(そこまで違わないと思う人もいるとは思うが)、それにログの順序を照らせばどちらがどちらをrebaseしたのか前後関係がわかり易いという点が挙げられるだろう(とは言え、これもメリットデメリットかは使用する状況や人によるところだろう)。デメリットは、一般的なマージに比べその使い方がやや直感的ではないことと、小さなうっかりが取り返しのつかないミスに繋がりやすいこと、またコンフリクトが発生してしまうと作業が止まってしまい、rebaseを使い慣れていないと立ち往生してしまう可能性があることなどが挙げられる。

個人的には通常まだpushしていない些末な(もしくはまだ綺麗にまとまっていない)コミットに対しては先にrebaseを使って整理してからpushすることが多い。ただしrebaseというのはログを修正するに等しいので、このコマンドによってパラレルワールドが生み出されてしまい、他の人に多大な迷惑をかけてしまう可能性も十分あり得る。なので既にpushした内容については、rebaseの使用は避けた方が賢明だろう。


問題:
マージをしようとしたらコンフリクト(Conflict)が起きてしまった。どう対処するのが望ましいか?

これはアウト

「トラブル発生でーす!はい、問題起こした人が自分で解決してくださーい!」

こうしてみよう

ブランチをマージしようとしたらコンフリクトが発生。こういう時多くの場合、作業の分担範囲をしっかりと確認していなかったことや、元々のフレームワーク設計が上手くいっていなくて皆が同じファイルの修正に取り掛かってしまっていたことが原因だったりする。通常コンフリクトが発生したら、当事者同士を呼んで話し合い、どちらのcodeを使うのかを決めて再びコミットすればいいだけのことだったりする。


問題:
git checkout SHA1git reset SHA1及びgit revert SHA1この3つのコマンドの違いを説明しなさい。

git checkout SHA1
このコマンドはHEADを指定したcommit上に移動させ、且つ現在の状態を指定したコミットの状態に戻すもの。ただし、ブランチを移動させるわけではない(つまりブランチは元の位置を保ったまま、HEADの位置が移動しただけの状態)。

なので、ログには全く変化はなく、単にHEADが指定した位置に移動したというだけのことである。

git reset SHA1
このコマンドはHEADとブランチを指定したコミット上に移動させるもの。同時にコマンドの後ろに追加したオプション(よく使うのは--mixed--soft--hardだ)によって、どのファイルやディレクトリを残し、どれを消すのかを決めることが出来る。デフォルトの--mixedはリセットをかけたファイルをワーキングディレクトリに残しておくことが出来るし、--softならばステージングエリアに残しておくことが出来、--hardならば問答無用にとにかくリセットしてしまう。共通して言えるのはどのオプションも、HEADの位置が変わるだけではなく、ログ全体にも変化を及ぼす(ログが短くも長くもなる)点だ。

git revert SHA1
このコマンドは新しくコミットを作り出し、その新しく生み出されたコミットによって特定のコミットを取り消してしまうこと(正確に言えばundo)が出来る。ただ、本質はコミットなのでGitログが短くなるということはなく、単にrevertが長くなるだけである。

ケーススタディ

問題:
もしうっかりまだマージしていないdevelopブランチを削除してしまった場合、どうすればいいだろうか?

これはアウト

「部長、ここに辞表置いときます」(重っ)

こうしてみよう

慌てなくて大丈夫。ブランチというのは付箋のようなものなので、ブランチを消してしまったからといって、例えそれがマージ前のブランチであったとしても、コミットまでもが消えたりすることはあり得ない。単にブランチという付箋が剥がされてしまったので、一時的に見えなくなってしまっただけで、またブランチの付箋を貼り直せばいいだけのことなのだ。例えば元々のブランチがこのような感じだったとして:

developブランチを試しに削除してみよう:

$ git branch -D develop

するとこのような状態になる:

まだ存在はしているものの、見えなくなってしまっただけ。なので、これらのコミットを見えるようにする為には、再びブランチという付箋を貼り直せばいいわけだ:

$ git branch new_develop 84aa2e6

これで元々のdevelopという付箋が剥がされてしまった位置に(ここでいう84aa2e6)再びnew_developという付箋が貼り直されたことで再度見えるようになった。

もしかしたら、その84aa2e6というのはどうやって探し出せばいいのと思ったかもしれない。種明かしをすると、これは通常ブランチを削除する際にこのようなメッセージが画面に表示されるので、わかるようになっている:

$ git branch -D develop
Deleted branch develop (was 84aa2e6).

ただよく見ていなかったり、うっかりメッセージ画面を消してしまったという時でも、git reflogから探し出せば、恐らく見つけられるはずだ。


問題:
うっかりgit reset --hardコマンドでファイルを消してしまいました、助かる方法はありますか?

これはアウト

「また新しくダウンロードし直せばよくない?(笑)」(うん…まぁそれでもいいんだけどさ)

こうしてみよう

大丈夫、基本的にGitのオブジェクトは憎まれっ子同様簡単に消えたりはしないから。オブジェクトは目には見えない方法でGit空間にきちんと保管されているので、git reflogコマンドでresetをくらった当該コミットのSHA1ハッシュ値を調べだした後、再びhard resetをかければ元通りになる。

git resetは覆水盆に返るのだ:)


問題:
git cherry-pickコマンドとはいつ使うべきものか?またどのように使えばよいか述べよ。

とあるブランチのとあるコミットだけ欲しい、ただしブランチ全体をマージしたくはないな(例えばそのブランチの他のコミットに問題があるとかで)という時、git cherry-pickコマンドを使えば欲しいコミットを現在のブランチの後に持ってくることが出来る。例えば:

$ git cherry-pick 6a498ec

このコマンドだと6a498ecというコミットを拾い出して、現在のコミットの後ろに持ってくることが出来る。また、一度に複数を持ってくることも可能で、その場合:

$ git cherry-pick fd23e1c 6a498ec f4f4442

このようにすれば一度に3つのコミットを持ってくることが出来る。
その他にもgit cherry-pickコマンドの後に--no-commitというオプションをつけると、コピーしてきたコミットを直接後ろにつけることはせず、とりあえずステージングエリアに置いておくことも出来る。


問題:
プロジェクト内に比較的敏感な又は機密性の高いファイルがあるとする(例/config/database.yml)。Gitを使用する際、こうしたファイルをどのように扱うのが妥当か述べなさい

これはアウト

$ rm config/database.yml

(これじゃあ元も子もないですやん…)

こうしてみよう

機密性の高いファイルだけに限らず、例えば書きかけで仮保存しているだけなのでまだGitに入れておくべきではないファイルというものだって存在する。こういう時、プロジェクト内に.gitignoreファイルを作っておいて、Gitの管理対象とするルールを設定しておけばいい。


問題:
とあるコードを誰が書いたのか知りたい時にはどうすればいいか?

これはアウト

グループライン等で皆に向かって「ここのXって部分のコード、誰が書いたんですかー!」と思い切って聞いてみる

こうしてみよう

$ git blame ファイル名

このコマンドを使えば、ファイル内の各コードは誰がいつ、どこのコミットに書き込んだのかが一目瞭然だ。


問題:
git push -fコマンドというコマンドを使ったことはあるだろうか。このコマンド、どのような状況下で使用するものか述べよ。

もちろん使ったことがある。しかも、すごく使えるやつだ。

時々プロジェクトのコミットログがぐちゃぐちゃなのに我慢が出来なくなって、rebaseコマンドでバッサバッサと整理したりするのだが、rebaseを使うというのは既に起きた事実を修正してパラレルワールドを作り出すことに等しいので、とてもじゃないけれどpushは出来ない。じゃあ、どうすればいいかというと、そういう時にこそgit push -fコマンドの出番だ。ただし、このコマンドを実行する前には必ず同じプロジェクトを扱うチームメイトに今後は自分がpushしたものに進度を合わせるよう一声かけてほしい。

また蛇足になるのだが、例えば一つタスクを終えた後、今しがたのコミットはあまりに細かすぎたなというような時、個人的にはrebaseを使ってブランチを整理することが多い。確かにrebaseはログを変えてしまうのだが、この場合影響を及ぼす範囲が自分のブランチだけに限られているので、安心して使うことが出来るからだ:

$ git push -f origin feature/my_cat

このように他人のブランチに影響を及ぼさず、影響範囲が自分だけに限定される時、git push –fは使っても問題ないといえる。ただし、状況がどうあれ、やはりこのコマンドを使う際には数十秒しっかり考えて、コマンドに間違いが無いかもしっかりと確認した上で、Enterキーを押すようにしてもらいたい。


問題:
チームで作業中、自分がpushしたコミットに問題を発見した。取り消したいのだが、どうすればいいか。

これはアウト

まずはこれ:

$ git reset HEAD^ --hard

続いて大技!:

$ git push -f

はい、これにて終了!

こうしてみよう

もしチームで開発を進めているのであれば、軽々しく共用ブランチにgit push –fをキメるのは絶対にやめておこう。既にpushしてしまった上に、そのコミットが他の人に使われている時、そんな時はrevertコマンドで当該コミットを取り消してみよう:

$ git revert SHA1

こうすれば自分が指定したコミットを取り消す新しいコミットを作成することが出来る。


問題:
もし特定のブランチ上で作業を進行中に、突然上司に呼ばれて別の箇所を修正するよう言われてしまった。こんな時、やりかけの仕事はどうすればいいだろうか?

幾つか方法があるのだが、まずは一先ずgit commitをしておき、トラブル処理が終わってから再びブランチに戻り、git resetをかけて先ほどのコミットの続きに取り掛かるというやり方が考えられる。

もう一つはgit stashコマンドを使用して、手元の仕事を一旦stash上に置いておき、トラブル処理が終わってから再びgit stash popもしくはgit stash applyコマンドを実行して先ほどの進度を呼び出すやり方もある。


問題:複数のコミットを一つにマージするにはどうしたらいいか?

これはアウト

まずはこれ:

$ rm -rf .git

ログを抹消して、初期化しておいてから:

$ git init

最後に全部一気にぶっこめば…

$ git add --all
$ git commit -m "add all files"

こうしてみよう

複数のコミットを一つにまとめたい時は、git rebaseコマンドのインタラクティブモードを使ってみよう:

$ git rebase -i SHA1

「インタラクティブモード」の時に、squashを選択してrebaseを実行すれば、複数のコミットを一つにまとめることが出来る。


問題:
例えばGitを使ったことがない上司に:「今さっき更新したファイルまとめて全部もらえない?」と言われた時、あなたならばどうする?

これはアウト

直接上司に「少しはGitの使い方覚えて下さいよ」もしくは「ああ、GitHub 上にあるんで、自分で見てみて下さい」と言ってみる

こうしてみよう

GUIソフト(SourceTree等)を開いて一つ一つ該当するファイルを選ぶ、もしくはターミナルコマンドを使って:

$ git diff-tree HEAD --name-only -r --no-commit-id

git diff-treeコマンドというのは、2つのコミット間の違いを比較してくれるもので、後ろにつけた--name-onlyというのは「ファイル名だけを羅列」すればいいという意味だ。-rオプションをつければディレクトリ、子ディレクトリ、孫ディレクトリと全部リストアップすることが出来る。

またSHA1ハッシュ値をつければ、Gitはこの当該コミットを1つ前の状態の時と比べてくれるので、HEADオプションをつければ最新のコミットと一つ前の状態を比較して異なるファイルリストを出してくれる。

その後は、git archiveコマンドを使えば、git diff-treeでリストアップされたファイルをまとめて圧縮ファイルにしてくれるので、それを上司に送ればミッションクリアというわけだ。


問題:
空のディレクトリはGitの管理下には置けないのだが、もしその空のディレクトリが重要なもので必ずGitの管理下に置きたいという場合、どうすればいいだろうか?

Gitというのは「ファイルの内容」によってバージョン管理をしているものなので、もしディレクトリ内に何もファイルが入っていないとなると、それはGitに認識されていないということになる(つまりは無視されている)。とにかくどんなファイルでもいいから1つ入れておけばいいのに、何も入れておくものが思いつかない、そんな時は.keepという空のファイルを入れておこう。


問題:
過去のとあるコミットから新たにコミットを切ることは出来るか?

幾つか方法がある:

まず第一に過去に戻る(例657fce7):

$ git checkout 657fce7

次にそこから新しいブランチを切る:

$ git branch my_cat

もしくはこのようにしても構わない:

$ git checkout -b my_cat

ただし、もっと簡潔にいきたければたった1行で済ませることも出来る:

$ git branch my_cat 657fce7

このコマンド「657fce7というコミット上にmy_catという名のブランチの付箋を貼る」という意味だ。


問題:
git pushコマンドを実行したところ、このようなメッセージが出た:

$ git push origin master
To /tmp/git-kata.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to '/tmp/git-kata.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

これはどのような意味か?またどのように解決すればいいか?

これはアウト

「これは簡単、フォースを使えば…解決出来ないものなどないわ!」

$ git push -f

こうしてみよう

こういうメッセージが表示されたのは、あなたがpushコマンドを実行する前に既に別の人がpushしてしまい、進度に食い違いが起こったことに原因がある。これは必ずしもコンフリクトが起こったからというわけではなく、コンフリクトがあるのかどうかはpullしてくればわかることだ。この問題の答え、実は上のエラーメッセージの中に既に答えが書かれている。こういう時は先ずgit pullコマンドを実行して、オンライン上の進度を引っ張ってくればいい(通常は自分の手元でマージを実行する)、そして問題がないことを確認した後に再びpushすればいいのだ。


問題:
時々過去のコミットを見返すと、こういうメッセージが表示される:

$ git checkout 5bca205
You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at 5bca205... add database config files

これはどのような意味か?またどのように解決すればいいか?

このメッセージ、パッと見はエラーメッセージのように見えるのだが、HEADがどのローカルブランチも指していないという状態を伝えるだけのもので、大した問題ではない。単にHEADを再びどこかのローカルのブランチを指すようにすればいいだけの話なのだ。例えば:

$ git checkout master

これで解決。

とはいえ、HEADはどこでもいいからどこかブランチを指していればいいかと言うとそうでもなく、例えばリモート上のorigin/masterブランチを指していたりすると、これも同様にdetached HEADのメッセージが表示されてしまう。


問題:
時々ブランチを切り換える際にこのようなメッセージが表示されることがある:

$ git checkout master
error: Your local changes to the following files would be overwritten by checkout:
index.html
Please commit your changes or stash them before you switch branches.
Aborting

この後もしスムーズにブランチを切り換えられなかった場合、どうすればいいだろうか?

エラーメッセージに表示された通り「Please commit your changes or stash them before you switch branches.」、もし今しがたの修正を手元に残しておきたいという場合は先にコミットを保存しておいてから、少ししてからresetを使って続きにあたってもいいだろう。もしくはgit stashを使って、その後からgit stash popもしくはgit stash applyで戻ってきて作業を続ければいい。

また、もしこれらの修正が不要だという場合はgit reset HEAD index.htmlもしくはgit checkout index.htmlでこれらの修正を取り消しにすることが出来るしgit checkoutにオプション-fをつければ直接ブランチを切り換えてくれる:

$ git checkout master -f

問題:
feature/developブランチをmasterブランチにマージしたのだが、どうすればこのマージを取り消すことが出来るか?

マージ前:

マージ後:

これはアウト

「まずは今しがた修正したファイルをコピーして別の場所に保存、その後新しいプロジェクトをcloneしてきて、最後にさっきのファイルを放り込めば、はい一丁あがり!」

こうしてみよう

実は新しくダウンロードし直してくる必要などなくて、単にブランチを「マージ前」の状態に戻せばいいだけのことだ。上の図を例に使うと、マージ前のmasterのコミットはbb92e0eなので:

$ git reset bb92e0e --hard

これでマージ前の状態に戻すことが出来た。もしくは、わざわざbb92e0eと打ち込まなくても「代名詞」を使って「相対する位置」に持ってくることが出来る:

$ git reset HEAD^ --hard

こうすればHEAD(bfd8e86)の「一つ前」のコミット、つまりbb92e0eの状態になったし、これで先ほどのマージを取り消したのと同じことになった。


問題:
feature/developブランチをmasterブランチにrebaseしたのだが、取り消したい。どうすればいいだろうか?

Rebase前:

Rebase後:

これはアウト

「またダウンロードし直せばいいじゃんね!ハハ」(うん、正直に打ち明ければ僕も同じことしたことあるよ…)

こうしてみよう

Rebaseは一般的なマージと違うので、もし直接git reset HEAD^ --hardを使っても思うような結果は得られない。比較的簡単な解決法は、ORIG_HEADのログを使ってrebase前の状態に戻すことだろう:

$ git reset ORIG_HEAD --hard

このORIG_HEADは直近の危険な操作(例えばreset、rebase、mergeなど)を行う手前の状態を記録しておいてくれる。ただし記録しておいてくれるのは直近のもの1つだけ。なので万が一うっかりと消してしまった場合は再度git reflogから探し出せば、きっとrebase前のコミットのSHA1ハッシュ値を見つけ出せるはずだ。その後は再びこのコマンドを実行して:

$ git reset REBAS前のSHA1ハッシュ値 --hard

これで先ほどのrebaseを取り消すことが出来た。


問題:
もしチーム内の誰かがgit push –fを発動してしまった場合、どうすればいいだろうか?

これはアウト

こうしてみよう

Gitは一種の分散式バージョン管理システムなので、皆それぞれ手元にそれぞれの進度で進めているプロジェクトがあるはずだ。なので、この場合自分もしくは他のチームメイトが再度手元にあるプロジェクトをgit push -fコマンドを実行してpushし、前回のgit push -fによってもたらされた被害を新たに覆いつくしてしまえばいい。

もちろん復旧作業を終えたら、やらかしたチームメイトと、なぜ事前通告なしにgit push -fコマンドを選択して実行したのかしっかりと話し合うことをおすすめする。

その他

問題:
まだ社内でGitもしくはその他のバージョン管理システムを導入していない場合、Git導入の為に何と言って上司を説得するか述べよ。

この問題に答えは用意していないので、各自自由に考えて差し支えなければ下のコメント欄に答えを書き込んでいってほしい。もしくはあなたの代わりに上司のもとへ説得に行くのも大歓迎。まずはメッセージを貰えれば、Git導入にどうやって着手していけばいいか相談にのります :)

最後に

原文(中国語)のリンク:
https://gitbook.tw/interview

やりたいことが今すぐわかる逆引きGit入門

もっと詳しく知りたい方は、拙著「やりたいことが今すぐわかる逆引きGit入門」をご参照ください。Amazonでの購入はこちらから:
https://www.amazon.co.jp/やりたいことが今すぐわかる-逆引きGit入門/dp/4798059595/

Why do not you register as a user and use Qiita more conveniently?
  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