Gitに入門する -その10-

blog.takanabe.tokyo

ステップ2の「Gitを初めからていねいに」をやる。

「みんなでつかう - push pull」より。


まずはゆうすけ

$ cd yusukes_workspace
$ git checkout -b feature/unify_styles development

git checkout -b <ブランチ名>
これでブランチを切ってそこに移動。
git checkout -b <ブランチ名> <ブランチ元>
これでブランチ元からブランチを切ってそこに移動。

こうだったのが↓

$ git branch
  development
* master

こうなる↓

$ git branch
  development
* feature/unify_styles
  master

準備が整ったので、
cat_lover_said.txtを編集してコミット。

$ git add cat_lover_said.txt
$ git commit -m 文体を統一
$ git graph
* 2843088  (HEAD -> feature/unify_styles) 2015-12-21 Yusuke 文体を統一
* 6ded966  (origin/master, origin/development, origin/HEAD, master, development) 2015-12-06 Takashi cat_lover_said.txtを追加

たかしに「頭おかしい」を急いで直せという指示

ゆうすけが文体を統一している間にたかしにも修正の指示が。

マスターブランチから hotfix ブランチを切る。

$ cd takashis_workspace
$ git checkout -b hotfix master
$ git branch
  development
* hotfix
  master

頭おかしいを修正してコミット。

$ git add .
$ git commit -m 頭おかしいという表現はまずいので修正

そして、手元のリポジトリの変更をリモートリポジトリに反映させる。
でもリモートリポジトリ側にhotfixブランチがない。
そんなときは、リモートリポジトリに新しいブランチを複製!です。
git push <リモートリポジトリの名前> <手元のブランチ名>:<リモートに作りたいブランチ名>

$ git push origin hotfix:hotfix
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To ../shared_repo.git
 * [new branch]      hotfix -> hotfix

大事なのは最後の2行らしいです。
shared_repo.gitに新しいブランチhotfixが作成された、と。

手元のリポジトリでのブランチ名とリモートリポジトリのブランチ名が同一の場合は、
下記でも可。
$ git push <リモートリポジトリの名前> <ブランチの名前>

みんなで触るリポジトリにhotfixブランチが作成できたので、
手元のhotfixブランチがこのリモートブランチを追跡するように設定。

$ git branch --set-upstream-to=origin/hotfix hotfix
Branch hotfix set up to track remote branch hotfix from origin.

続いて、共有リポジトリの master にマージする。
だがしかし、共有リポジトリを直接いじることはできない。
なので、「追跡ブランチ」を変更する。
まず、hotfixの内容を手元のmasterブランチにマージする。

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

現在の状況

$ git graph
* bb5bd8a  (origin/hotfix, hotfix) 2015-12-21 Takashi 頭おかしいという表現はまずいので修正
* 6ded966  (HEAD -> master, origin/master, origin/development, development) 2015-12-06 Takashi cat_lover_said.txtを追加

マージする

$ git merge --no-ff hotfix
Merge made by the 'recursive' strategy.
 cat_lover_said.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

マージ後の状況

$ git graph
*   89b28a9  (HEAD -> master) 2015-12-21 Takashi Merge branch 'hotfix'
|\
| * bb5bd8a  (origin/hotfix, hotfix) 2015-12-21 Takashi 頭おかしいという表現はまずいので修正
|/
* 6ded966  (origin/master, origin/development, development) 2015-12-06 Takashi cat_lover_said.txtを追加

最新のコミットが手元にしかないので、
origin/masterが最新を示していない。

ここでgit status

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean

あなたのブランチは2コミット先に行っています。
あなたのコミットを公開するにはgit pushしてください、とのこと。

というわけでgit pushする。

$ git push
warning: push.default is unset; its implicit value has changed in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the traditional behavior, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

When push.default is set to 'matching', git will push local branches
to the remote branches that already exist with the same name.

Since Git 2.0, Git defaults to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

Counting objects: 1, done.
Writing objects: 100% (1/1), 221 bytes | 0 bytes/s, done.
Total 1 (delta 0), reused 0 (delta 0)
To ../shared_repo.git
   6ded966..89b28a9  master -> master

まとめると、
push.default が設定されてないからどっちかの設定をしろと。
①git config --global push.default matching
②git config --global push.default simple

matching:手元にあるすべての追跡ブランチの変更をリモートに反映する
simple:今選択されているブランチが追跡ブランチであれば、手元のブランチの変更内容をリモートに反映する

そんで現在の状況

$ git graph
*   89b28a9  (HEAD -> master, origin/master) 2015-12-21 Takashi Merge branch 'hotfix'
|\
| * bb5bd8a  (origin/hotfix, hotfix) 2015-12-21 Takashi 頭おかしいという表現はまずいので修正
|/
* 6ded966  (origin/development, development) 2015-12-06 Takashi cat_lover_said.txtを追加

origin/masterも最新になりました。
無事にリリースも終わりましたとさ。

次にやるのは、
・hotfix ブランチはもう用無しなので、手元からもリモートからも消してしまう
・緊急リリースによる変更内容を、開発ブランチにも反映させる

$ git branch -d hotfix
Deleted branch hotfix (was bb5bd8a).

手元のブランチが消えました。
ではリモートブランチも消しましょう。
origin/hotfixを消すので追跡ブランチを消す必要があるけど、
今消しちゃったんでないです。
そういう場合は、
$ git push origin :hotfix
これです。
リモートブランチを作るコマンド:
$ git push <リモートリポジトリの名前> <手元のブランチ>:<リモートに作るブランチ>
リモートブランチを消すコマンド:
$ git push <リモートリポジトリの名前> (ここになにも書いてない):<リモートのブランチ>
何もないもので上書きする、つまり、消えるってことです。

$ git push origin :hotfix
To ../shared_repo.git
 - [deleted]         hotfix

これで手元からもリモートからも消えました。
そしたら、hotfixの変更が反映されているmasterの内容をdevelopmentに反映します。

$ git checkout development
$ git merge --no-ff master

手元のdevelopmentをあげる準備ができたので、

$ git push

完了です。

作業中だったゆうすけに戻る

$ cd yusukes_workspace
$ git graph
* 2843088  (HEAD -> feature/unify_styles) 2015-12-21 Yusuke 文体を統一
* 6ded966  (origin/master, origin/development, origin/HEAD, master, development) 2015-12-06 Takashi cat_lover_said.txtを追加

文体を統一する作業を終えて、手元のリポジトリにコミットしたとこまでだったので、
リモートリポジトリにアップします。

$ git push origin feature/unify_styles
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 873 bytes | 0 bytes/s, done.
Total 6 (delta 1), reused 0 (delta 0)
To ../shared_repo.git
 * [new branch]      feature/unify_styles -> feature/unify_styles

そしたら、最新の開発版にこれを反映させるために、developmentブランチにマージします。
ただし、
共有リポジトリのdevelopmentブランチには、すでにたかしが変更を加えているので、
たかしが行った変更をgit fetchで持ってくる必要がある。

$ git fetch origin
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 5 (delta 3), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From ../shared_repo.git
   6ded966..d3dee2e  development -> origin/development
   6ded966..89b28a9  master     -> origin/master

これでリモートリポジトリの内容がリモートブランチとしてコピーされてきました。
git graphでリモートリポジトリのコミットとブランチが取り込まれたか確認。

$ git graph
*   d3dee2e  (origin/development) 2015-12-21 Takashi Merge branch 'master' into development 緊急対応で行った修正をmasterから取り込む
|\
| *   89b28a9  (origin/master, origin/HEAD) 2015-12-21 Takashi Merge branch 'hotfix'
| |\
|/ /
| * bb5bd8a  2015-12-21 Takashi 頭おかしいという表現はまずいので修正
|/
| * 2843088  (HEAD -> feature/unify_styles, origin/feature/unify_styles) 2015-12-21 Yusuke 文体を統一
|/
* 6ded966  (master, development) 2015-12-06 Takashi cat_lover_said.txtを追加

リモートブランチと手元のブランチを比べてみると、
手元のブランチは昔のコミットを指しています。
リモートで行われた変更を手元に反映させるために「Fast-forward」で進めないといけません。

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
$ git merge origin/master
Updating 6ded966..89b28a9
Fast-forward
 cat_lover_said.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git checkout development
Switched to branch 'development'
Your branch is behind 'origin/development' by 3 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)
$ git merge origin/development
Updating 6ded966..d3dee2e
Fast-forward
 cat_lover_said.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

これで手元のリポジトリがリモートに追いついたので状況を確認。

$ git graph
*   d3dee2e  (HEAD -> development, origin/development) 2015-12-21 Takashi Merge branch 'master' into development 緊急対応で行った修正をmasterか                                ら取り込む
|\
| *   89b28a9  (origin/master, origin/HEAD, master) 2015-12-21 Takashi Merge branch 'hotfix'
| |\
|/ /
| * bb5bd8a  2015-12-21 Takashi 頭おかしいという表現はまずいので修正
|/
| * 2843088  (origin/feature/unify_styles, feature/unify_styles) 2015-12-21 Yusuke 文体を統一
|/
* 6ded966  2015-12-06 Takashi cat_lover_said.txtを追加

さて、いちいちこうやってリモートリポジトリの内容を取得してきて、手動で merge するのは正直だるいですね。だるすぎです。そのために用意されているの git pull です。

git pull は、「fetch してマージ」という一連の動作を自動でやってくれます。普段はこちらを使うと良いでしょう。ただし、気をつけてください。さきほど "git pull は「fetch してマージ」をという一連の動作を自動でやってくれる" といいました。そうです、「マージ」を行うのです。そのため、git pull を行うと「コンフリクト」が起こる可能性もあります。でも、もうあなたはコンフリクトがおこったおきにどうすればいいか、知っていますね。なら怖がらなくても大丈夫。落ち着いて競合を直し手動でマージコミットを作ればいいのです。

当然、このマージコミットは「手元」にしかないマージコミットなので、適切に共有リポジトリに push する必要も出てくるでしょう。でも、もうあなたはリモートリポジトリと手元のリポジトリの関係を適切にハンドルすることができるようになっています。これもなにも怖くないですね。


手元のリポジトリが最新になったので、
feature/unify_stylesの変更をdevelopmentに反映する。

$ git checkout development
Already on 'development'
Your branch is up-to-date with 'origin/development'.
$ git merge feature/unify_styles
Auto-merging cat_lover_said.txt
CONFLICT (content): Merge conflict in cat_lover_said.txt
Automatic merge failed; fix conflicts and then commit the result.

コンフリクトがでました。

$ git status
On branch development
Your branch is up-to-date with 'origin/development'.
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   cat_lover_said.txt

no changes added to commit (use "git add" and/or "git commit -a")

git addしてgit commitしましょう。

$ git add .
$ git commit
[development 1d1a818] Merge branch 'feature/unify_styles' into development

そしたら共有リポジトリにpushします。

$ git add .
$ git commit
[development 1d1a818] Merge branch 'feature/unify_styles' into development
$ git push
warning: push.default is unset; its implicit value has changed in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the traditional behavior, use:

  git config --global push.default matching

To squelch this message and adopt the new behavior now, use:

  git config --global push.default simple

When push.default is set to 'matching', git will push local branches
to the remote branches that already exist with the same name.

Since Git 2.0, Git defaults to the more conservative 'simple'
behavior, which only pushes the current branch to the corresponding
remote branch that 'git pull' uses to update the current branch.

See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)

Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 542 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To ../shared_repo.git
   d3dee2e..1d1a818  development -> development

終了!