$ git push origin develop
To
! [rejected] develop -> develop (non-fast-forward)
error: failed to push some refs to ''
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
GitMaster - http://sunstripe.main.jp/GitMaster
関連情報
はじめに #17 TODO #81
コンセプト
目的
応用、発展などを紹介する
状態
機能一覧
画面一覧
head
header
main
contents
応用編 - expansion
ここでは、様々なGit操作において応用となる(プロの現場)でもよく活用することを紹介していきます。
応用編
expension -> expension.html
expansion(応用編)
[ ] 詳細説明:このサイトの詳細説明
リポジトリの共有
変更履歴を統合
ブランチ戦略
ブランチとは
統合ブランチとは
リリース版が何時でも作成可能なようしておくためのブランチです。 また、トピックブランチの分岐元としても使用するため、常に安定した状態を保つ必要があるため、Jenkins等のCIツールを使用した自動ビルドやテストで、品質担保すると良いでしょう。 何らかの変更や機能追加を行う場合は、この統合ブランチからトピックブランチを作成して作業を行います。 (Subversionで言う、trunkと概念は同じです。Gitではmasterを指すことが多いです。)
トピックブランチとは
機能追加やバグ修正といったある課題や特定の目的実現に関する作業を行うために作成するブランチです。 複数の課題に関する作業を同時に行う時は、その数だけトピックブランチが作成されます。 トピックブランチは統合ブランチから分岐する形で作成され、作業が完了したら統合ブランチに取り込まれます。
(参考)git flow Gitを活用したブランチ運用戦略のモデルケースの1つです。(git flowとは) その他にもgithub flowという、git flowを簡略化したモデルケースもあります。 それらの違いについては、以下のQiitaの記事が簡潔にまとまってたので、参考にしてみてください。1
git flowとは? -> expansionGitFlow github flowとは? -> expansionGitHubFlow
ブランチの切り替えとブランチの統合 ブランチ戦略を実施するにあたって、具体的にどのようにブランチを新規作成し、作業が終わったブランチをどのように統合ブランチに取りこむかを説明します。
ブランチの切り替え Gitでは、下記のコマンド実行することで、ブランチの新規作成・切り替えを行います。
git branch(ブランチの作成) トピックブランチを作成する。 git branch:新規ブランチを作成
git checkout -b :新規ブランチを作成し、そのブランチに切り替える
git checkout(ブランチの切り替え)
作業するブランチを切り替える。
git checkout :指定したブランチにローカルブランチを切り替える
ブランチの統合(rebase)
統合ブランチにトピックブランチを取りこむ方法は、rebaseとmergeの二つがあります。 まずはrebaseについて説明します。
rebaseとは、その名の通り、「baseを再定義」します。 大まかな流れを説明していきます。
image.png
現在の情報を整理すると以下になります。
【masterブランチ】 ・リリースなどに活用されているブランチ。 ・他からの変更も取りこんでおり、現在の最新バージョンは「D」(バージョン名は便宜上です)。
【developブランチ】 ・masterブランチのバージョン「B」から分岐したbugを修正するためのブランチ ・developブランチには、masterブランチのバージョン「B」をベースに、X,Yという2つのバグ修正コミットを実施した。
この状態でbugfixブランチで、 rebaseコマンドgit rebase/<branch name(今回はmaster)>
を実行し、「masterブランチの最新コミットでbaseを再定義」すると以下のようになります。
image.png
developブランチの起点となるmasterブランチのバージョンが「B」から「D」に変更されます。 その際に、これまでのbugfixで変更していたコミット「X,Y」は「X',Y'」になります。 これは、rebaseを実行することで、bugfixでコミットされていた内容はそのままに、「baseを付け替えたことによって、X,Yは別コミットと認識され、コミットハッシュ値が変更」されるためです。
rebaseした時点では、bugfixブランチ内にはmasterブランチの最新の情報+bugfixの修正が取りこまれている状態なので、「X',Y'の変更をmasterブランチにmergeして取りこむ」必要があります。 しかし、mergeに際して、bugfixのリモートリポジトリにrebaseしてC,Dのコミットを取りこんだ結果をpushする必要がありますが、通常通りにpushした場合は以下のようなエラーが発生します。
$ git push origin develop To
! [rejected] develop -> develop (non-fast-forward)
error: failed to push some refs to ''
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
これはnon-fast-forward(大まかに言うと、ローカルのコミット情報がリモートリポジトリの最新コミットに対して単純に付け足せる状態になっていない)のためエラーが発生しています。 原因は、rebaseしたことにより、X,Yのコミットが無くなり、X',Y'というGitが認識していないコミットが生成されたため、単純に取りこめなくなったためです。 対処するには、 git push -f origin developのように -fオプション(forceプッシュ)をつけて強制的に上書きするしかありません。
無事mergeが完了したら、以下のようなツリーになります。
ブランチの統合(merge) rebaseが、平たく言うと統合ブランチの先頭にトピックブランチの情報を付け加えることだとすると、mergeは統合ブランチとトピックブランチの両方の変更を取りこんだマージコミットを作成し、統合ブランチの先頭がそのコミットに移動します。
image.png
上記のようなツリー構造をしている場合に、mergeコマンドを実行すると、以下のような構造になります。
image.png
rebaseとmergeの違い rebaseとmergeはどちらもブランチを統合させる動きをしますが、「履歴管理」で差異があります。 ・rebase:履歴は単純になるが、元のコミットから変更内容が変更される。 そのため、元のコミットを動かない状態にしてしまうことがある。 ・merge:変更内容の履歴はそのまま残るが、履歴が複雑になる。
どちらを採用するかは、開発の運用次第にはなりますが、使い分ける場合は以下のように分類すると良いと思います。
・トピックブランチを主語として、 統合ブランチの最新のコードを取りこむ場合:rebase (GitHubやGitLabを使っている場合は、rebaseしたトピックブランチを統合ブランチに対してPull/Merge Requestを出すことになるイメージです) ・統合ブランチを主語として、 特定のトピックブランチの変更を統合ブランチに取り込む場合:merge (素のGitを使う場合は統合ブランチからトピックブランチのコミットを取る動きになるため、こちらを使う機会が多いと思います)
footer
ad
page
footer