photo by Jennifer Duda
はじめに
ちょっと前に面白いことに気がついた。開発に携わる友人たちの多くがGitというツールの重要性はよくよく分かっているのに、それが一体どういうツールなのかを時間をかけて分かろうとはしていないということだ。とは言っても、プログラマーとしてのサバイバルスキル的な観点から言えば、Gitは例えば演算法やデータ構造、他のプログラミング言語やフレームワーク開発のように深入りして学ぶ必要はなく、多くの人が日常的に必要なGitの操作といえばadd
にcommit
、push
、pull
、それに加えてブランチを切ることとマージが出来さえすれば十分といったところだろう。そういうこともあって、求人中の会社にとってGitを使えるというアピールポイントは採用を決めるにあたって「少しプラスに加味される条件」に過ぎず、使えないとかよく知らないからといって、すぐさま採用に影響があるとは言えないところだ。
うん…確かに今のところ職場でのGitの立ち位置というのはそんな感じだ。そんなわけだから、GitをFTP代わりに使うのもあながち間違っているとは言い切れない。…言い切れないのだが、だがしかし!開発に携わる、とりわけチーム開発に携わる人間にとっては、不正確な使用法は時折ファイルに予期せぬ混乱と喪失を招き、しかもチームのメンバーにも多大なる迷惑をかけかねない。
というわけで、自分が面接官だったら面接者に聞きたいなという採用試験の例題を幾つか用意してみた。この例題は「私Git使えます!」という開発者であれば、たぶん…たぶん問題なく答えられるのではないかと思うので、是非採用試験前の参考にしてみてほしい。もし、採用試験時にここに用意した例題以外でも面白い問題があったという人がいたら、是非下のコメント欄に報告をお願いします。
免責事項:
- これはどこかの企業の面接試験の過去問とかいった類のものではありませんので、就職及び転職活動にあたっては各自しっかりと準備をして下さい。試験に全く違うことが出て、結果不採用であったとしても責任は負いかねます。
- もし万が一台湾の弊社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 clone
、git fetch
とgit 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 fetch
にgit merge
コマンドを加えたものだという言い方をすることが出来る。
問題:
GitにおけるHEADとは一体何か?
HEADというのは本質的には一つのタグに過ぎず、通常特定のローカル上のブランチやコミットを指している。なので、HEADは今いるブランチ(current branch)を指すものと考えてもらって構わない。
問題:
マージ後のブランチは通常どのように処理するのが適切か?また、それは何故か?
ブランチというのは、本質的には40桁のファイルに過ぎず、ブランチやファイルまたはコミットを削除したからといって消えるものではない。なので、マージ後のブランチを削除しようが、記念にとっておこうが実はどちらでも構わない。逆に言えば、取っておいたとしてもたかだが40Bytesの空間を占領するだけのことなので、数十、数百ギガの動画ファイルなんかと比べれば…というわけだ。
問題:
マージ済のブランチを削除してしまうと何が起こる?
ブランチというのは実はタグや付箋のようなものに過ぎず、特定のコミットの上に貼られているだけに過ぎない。つまりブランチはディレクトリやファイルといった類のものではない(確かに幾つかのバージョン管理システムではそういう形式をとるものも存在する)。Gitでは、削除されたブランチというのはちょうど、箱の上に貼られたシールを剥がすようなもので、シールを剥がしてしまったからといって箱自体に影響があるわけではない。つまり、マージ済のブランチを削除してしまったからといってどうってことはなく、ファイルやディレクトリまでが消えてしまうというような事態は起こらない。
問題:
git diff
このコマンドは一体どんな時に使うものか?
このコマンドは2つのコミット間の差異を比較したい時に使用する。例えば:
$ git diff e37078e d4d8d9d
こうすると、e37078e
とd4d8d9d
という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 SHA1
、git 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入門」をご参照ください。Amazonでの購入はこちらから:
https://www.amazon.co.jp/やりたいことが今すぐわかる-逆引きGit入門/dp/4798059595/