アリスがチャレンジなコードを書く時、git branchをちゃんと理解したい!



アリスとボブのGitシリーズが本になりました!
  アリスとボブのGit入門レッスン


アリスは迷っていた。現状のshowメソッドは固定されたメッセージしか出力しないが、理想的にはユーザーの条件によって変化させたいと。
しかし、その機能を実装するためには結構な大改修になってしまう。果たして今の自分の技術でちゃんと完了させることが出来るだろうか?この機能追加をやるべきか、このままにするか...。

  • アリスはこの修正が失敗に終わった時のことを考えて、ボブに連絡しておくことにした。「失敗したらごめんね。」と。(なんて無責任なアリス...。)
  • 連絡を受けたボブは、アリスの機能追加には大賛成。ボブ:「ただし、新しいブランチを追加して、そこで作業くれ。」と。アリス:「ブランチ???」
  • アリスはブランチを理解できていないが、とりあえず、ボブに説明された手順をそのままやってみることにした。アリス:「習うより、慣れろだわ」
alice/project$ git branch challenge #ブランチchallengeを作成
alice/project$ git branch           #ブランチの一覧を確認
   challenge
 * master
  • ブランチの一覧を確認すると、今作成した「challenge」と、「master」が確認できる。
  • ブランチ「master」はgitがデフォルトで作成するブランチ。最初はみんなmasterから始まる。
  • ブランチ名の先頭に「*」マークが付いているので、現在作業中のブランチは「master」ということになる。
alice/project$ git checkout challenge #ブランチを「challenge」に変更
Switched to branch "challenge"
alice/project$ git branch             #ブランチの一覧を確認
 * challenge
   master
  • ブランチの一覧を確認すると、ブランチは「challenge」に変更された。

challengeブランチでのアリスの修正

  • ブランチが切り替わったことを確認して、アリスはコードの修正を始めた。
# About git
Class WhatIsGit
  def show
    puts 'Do you understand the basis of git? [yes/no]'
    input = gets.chomp.downcase
    case input
    when 'yes', 'y'
      puts 'Git is easy.'
    else
      puts 'Git is difficult...'
    end
  end
  
  def about(lang = 'en')
    puts "http://#{lang}.wikipedia.org/wiki/Git"
  end
end
  • ひとまず完成したので、コミット。
alice/project$ git commit -a -m 'challenge commit 1'
Created commit 472085b: challenge commit 1
 1 files changed, 8 insertions(+), 1 deletions(-)
  • アリスがじっくり考え直すと、もっと簡潔に書くべきと感じたので、さらに修正。
# About git
Class WhatIsGit
  def show
    case input('Do you understand the basis of git? [yes/no]')
    when 'yes', 'y'
      puts 'Git is easy.'
    else
      puts 'Git is difficult...'
    end
  end
  
  def about(lang = 'en')
    puts "http://#{lang}.wikipedia.org/wiki/Git"
  end
  
  private
    def input(message)
      puts message
      gets.chomp.downcase
    end
end
  • これで良し、コミット。
alice/project$ git commit -a -m 'challenge commit 2'
Created commit 31ce330: challenge commit 2
 1 files changed, 7 insertions(+), 3 deletions(-)

ブランチを切り替えてみる

  • アリスは、challengeブランチでの作業が一段落したので、masterブランチに切り替えてみた。
alice/project$ git checkout master
Switched to branch "master"
  • すると、what_is_git.rbの内容が、以前の状態に戻ってしまった...。
  • アリスは一瞬焦ったが、もう一度challengeブランチに切り替えてみると、さっき書いたコードが復元された!
alice/project$ git checkout challenge
Switched to branch "challenge"
  • つまりgitに管理されたディレクトリにおいては、what_is_git.rbというファイルは、編集作業をするための一時的なコピーでしかないのだ。
  • gitがコミット時点のスナップショットを脈々と保存している.gitフォルダの履歴がすべてであり、
  • 今やその履歴は、masterと、そこから分岐するchallengeという二つの系統に分かれているのだ。
イメージ図
過去 <----------------------> 未来

           o--o <-- challengeブランチ
          /
...o--o--o <------- masterブランチ

oはコミット、またはマージを表す

ボブの修正

  • ちょうどその頃、ボブは重大なバグを見つけていた。ボブ:「クラス宣言のclassが大文字で始まっていたとは...」
bob/myrepo$ git diff
 diff --git a/what_is_git.rb b/what_is_git.rb
 index ac3f723..bec373b 100644
 --- a/what_is_git.rb
 +++ b/what_is_git.rb
 @@ -1,5 +1,5 @@
  # About git
 -Class WhatIsGit
 +class WhatIsGit
    def show
      puts 'Git is difficult, if you understand the basis.'
    end
bob/myrepo$ git commit -a -m 'class downcase'
Created commit 87f0ad7: class downcase
 1 files changed, 1 insertions(+), 1 deletions(-)
bob/myrepo$ git push shared master
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 281 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/Shared/project.git
   16150ca..87f0ad7  master -> master
  • すぐさま修正して、コミット、プッシュ。

challengeブランチでのアリスの迷走

  • 一方、アリスはchallengeブランチのコードをテストしていた。
alice/project$ git checkout challenge
Switched to branch "challenge"
alice/project$ irb
 >> require 'what_is_git'
 SyntaxError: ./what_is_git.rb:21: syntax error, unexpected kEND, expecting $end
 	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `gem_original_require'
 	from /Library/Ruby/Site/1.8/rubygems/custom_require.rb:27:in `require'
 	from (irb):1
 >> 
  • しかし、requireからして実行できない...。やはり私(アリス)には無理だったのか?アリスは落胆していた。
  • その時、ボブから連絡があった。重大なバグを修正したと。これを取り込まないとすべてのテストがエラーになると。
  • アリスは早速、共有リポジトリからプルした。なんと、クラス定義の先頭が大文字になっていたとは。ダメだこりゃ。
alice/project$ git checkout challenge
Switched to branch "challenge"
alice/project$ git pull shared master
From /Users/Shared/project
 * branch            master     -> FETCH_HEAD
Auto-merged what_is_git.rb
Merge made by recursive.
 what_is_git.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
alice/project$ git diff HEAD^
 diff --git a/what_is_git.rb b/what_is_git.rb
 index 8fe919a..559d6cb 100644
 --- a/what_is_git.rb
 +++ b/what_is_git.rb
 @@ -1,5 +1,5 @@
  # About git
 -Class WhatIsGit
 +class WhatIsGit
    def show
      case input('Do you understand the basis of git? [yes/no]')
      when 'yes', 'y'
  • すぐさま修正を取り込んで、irbでテストしてみた。
alice/project$ irb
    
=> true
=> #<0x365b8c>