
Gitの使用に関する一連の記事の最後の部分では、ブランチに関する議論を続け、プッシュコマンドを使用する機能を検討し、リベースとは何かを説明します。 リンクを使用して、シリーズの最初と2番目の記事を読むことができます。
第16章ブランチはどこから来たのですか?
私たちは忍耐力を獲得し、さまざまな労働状況を引き続き検討します。 いくつかのコミットを行ってからfetchコマンドを実行すると(新しいコミットをダウンロードしますが、まだ作業ディレクトリに適用しないでください)、少しわかりにくい画像が表示されます。

どのようなブランチが判明しましたか? ブランチを作成しませんでした。 従業員の1人が作成したのでしょうか? いいえ、誰も作成しませんでした。 イベントの年表を復元しましょう:
- 最初に、新しいコミットをダウンロードしました。 その後、最後のコミットは「2」でした。
- 次に、コミットを「3」と「4」にしました(ただし、これまでのところ、プッシュしませんでした)。
- この時点で、他の従業員がコミット「5」、「6」、および「7」をリモートリポジトリにプッシュしました。 それから私たちはそれについて何も知りませんでした。
- 最後に、フェッチを実行して、画像にあるものを確認しました。
Gitでは、各コミットは前のコミットへのリンクを保存します(これにより、図の円を接続できます。各セグメントは前のコミットへのリンクです)。 コミットを「3」にしたとき、最後のコミットは「2」であったため、それらは接続されています。 しかし、誰かがオリジンで「5」のコミットを開始したとき、最後は「2」のコミットでもありました。結局、私たちはまだ「3」と「4」のコミットを開始しておらず、オリジンにはコミットがありませんでした その場合、コミット "5"の場合、コミット "2"も前のコミットとして機能し、Gitはこの接続そのものを記憶しています。
合計で異なる人々が互いに独立して、コミット「2」の結果を変更しました-それがブランチでした。 ちなみに、このブランチはローカルリポジトリにのみあります。 元々はまだ「3」と「4」のコミットなのでまだ実行されていません。
次は? プルではなくフェッチを行ったため、ダウンロードしたコミットは作業ディレクトリにまだ適用されていません。 それらを適用しましょう-このためにマージを実行します。 結果を図に示します。

起こったことはすでに私たちによく知られています。 自動マージコミット「8」が形成されました-マスターとヘッドはそれを指します。 作業コピーは、コミット「5」、「6」、および「7」からの変更を示し、コミット「3」および「4」からの変更と組み合わされました。 origin / masterは、最後の操作がローカルコンピューターで行われたため、まだ "7"を指しています。 そして、オリジン/マスターは、リポジトリがオリジンと通信した後にのみ移動できます。
最後に、プッシュを実行します。現在、origin / masterは「8」もポイントしています。
- merge-commit "8"がoriginに送信されます。
- そこで彼は最後になりました。つまり、リモートマスターポインターがそれを指すようになりました。
- リモートポインターマスターに関する情報がダウンロードされ、それがオリジン/マスターとして表示されます。
そこで彼は「8」を指しています。 論理的です。
これらの説明をスキップしたいという意欲に抵抗してください。 それらに複雑なものは何もありません、注意だけが必要です。 すべてがこのように機能する理由を理解するまで、手順を必ず確認してください。
Chapter 17.プッシュでエラーが発生するのはなぜですか?
Gitがpushコマンドでエラーをスローするという事実にきっと遭遇するでしょう。 問題は何ですか? なぜ彼は私たちのコミットを受け入れないのですか? プッシュは、Gitがオリジンに送信されたコミットごとに先行を見つけることができる場合にのみ成功します。 例:

ここで左側はローカルリポジトリのコミットで、右側はリモートリポジトリ(オリジン)のコミットです。
これらのコミットの年表は次のとおりです。
- 最初に、オリジンにはコミット「1」と「2」がありました。
- プルしました(これら2つのコミットのみがローカルリポジトリに表示されました)。
- 次に、ローカルリポジトリに「3」と「4」をコミットしました(プッシュしませんでした)。
- 誰かが起源で「5」のコミットを開始しました。
そして、今ではそれが写真にあることが判明しました。 わかった?
これで、「3」と「4」を元にプッシュしようとする試みは失敗します。 ローカルでは、コミット「3」の前身はコミット「2」であるため、Gitはオリジンの最後のコミット「5」へのコミットのドッキングを拒否します。 Gitの場合、前任者が同じであることが重要です。
問題は簡単に解決されます。 プッシュする前に、プルします(コミット「5」を自分で取得します)。 ここで質問することができます: また、なぜGitはコミット「5」を削除しますが、「3」および「4」コミットを送信できませんか? 状況は両方向で対称的であるようです。」 正しい質問です! そして答えは簡単です。 このような状況でGitがコミット「3」と「4」の送信を許可した場合、オリジン側でマージを行う必要があります。そこで競合を解決するのは誰ですか? 誰も。 したがって、Gitは最初に自分用の新しいコミットを取得し、コンピューターでマージを行い(競合がある場合は解決します)、プッシュコマンドで完成した結果を送信できるようにします。 同時に、起源の競合が発生することはなくなります。
pullコマンドでコミット「5」を選択した後、ローカル履歴がどのようになるかを見てみましょう。

ここで、前の図のように、「3」と「5」には祖先「2」があります。 また、新しいコミット「6」はマージコミットであり、以前から認識されていました。
この状態では、ローカルコミットが既にトリガーされている可能性があります。 ここに歴史の分岐が現れましたが、両方の分岐は合併時に合併しました。 したがって、ブランチのヘッドは再び単独です。 つまり、プッシュを妨げるものは何もありません。 その後、元々、コミットはまったく同じ「ループ」に見えます。
プッシュによってエラーが発生するようになったので、その理由と対処方法はすでにわかっています。
第18章リベース
前の章では、いくつかのローカルコミットを行った後、プルチームが他の従業員のコミットをリモートリポジトリから取得しました。 私たちのローカルリポジトリでは、「ブランチ」が形成され、メインブランチにマージされました。 プッシュ後、この一時的な分岐は起源になり、従業員はそれをダウンロードして履歴に表示します。 多くの場合、このような「ループ」は望ましくないと見なされます。 なぜなら、美しい直線的なストーリーの代わりに、見づらくなるループがたくさんあるからです。
Gitは代替手段を提供します。 上記ではフェッチ+マージを行いました。 最初のチームは新しいコミットを選択し、2番目のチームはそれらをコミットされていないコミット(存在する場合)と結合し、マージの結果でマージコミットを作成します。
したがって、fetch + mergeの代わりにfetch + rebaseを実行できることがわかります。 リベースとは何ですか?マージとはどう違いますか? 前の例でどのようにマージが行われたかをもう一度思い出してください。

Rebaseの動作は異なります。コミットされていないコミットのチェーンを祖先から切断します。 これらはコミット「3」と「4」であることを思い出してください。 祖先「2」から切断し、リベースして、ダウンロードしたばかりのコミット「5」の「上」に置きます。 つまり、「3」と「4」が上から「5」にアタッチされます(マージコミット「6」はまったく表示されません)。 結果は次のようになります。

もうループはありません。ストーリーは直線的で美しいです! 長いライブリベース! オリジンからコミットをダウンロードする場合、マージよりもリベースを使用してローカルコミットと結合する方が良いことがわかりました。
まあ、それがあなたのコミットのカップルではなく、新しい機能の開発を伴う大きなブランチについてです。 この機能をメインブランチに追加するときが来たら、リベースまたはマージを介してそれをどのように行うのが最善ですか? どちらの方法にも利点があります。
- rebaseは履歴をシンプルかつ線形に保ちます-ブランチからメインブランチの最後までコミットのチェーンを追加します。
- mergeはループを作成しますが、機能の開発の履歴は履歴でより明確に追跡されます。
そのような場合は、リベースまたはマージ設定をプロジェクトのリードプログラマーと話し合ってください。
第19章エピローグ
あなたと私は、リポジトリを操作するための多くのGitコマンドを見つけました。
- 引く
- コミットする
- 押す
- 加える
- クローン
- チェックアウト
- 隠れる
- 併合する
- リベース
- 中止する
- フェッチ
これらは、仕事に必要なすべてのチームではなく、最も頻繁なチームだけです。 他の人を習得する必要があることに備えてください。 さまざまなgitクライアントを使用してGitを操作できます。 主に次の3つを使用します。
- カンチレバー
- ソースツリー
- べっこう
顧客の選択は好みの問題です。
コンソール-すべてのプラットフォームで動作しますが、非常に禁欲的なインターフェースを備えています。 コンソールでの作業に慣れていない場合、ほとんどの場合、コンソールで不快に感じるでしょう。
SourceTreeは、かなりシンプルなインターフェースを持つグラフィカルクライアントです。 主なプラットフォームには、WinとMacのバージョンがあります。 しかし、従業員はしばしば彼の遅い仕事と不具合について不平を言います。
TortoiseGitは別のグラフィカルクライアントです。 Mac用のWin用のバージョンがあります。 インターフェイスはやや珍しいですが、多くの人が気に入っています。 グリッチとブレーキに関する苦情は、SourceTreeの場合よりも大幅に少なくなります。
興味深いことに、SourceTreeとTortoiseGitはどちらもGitリポジトリと直接連携しません。 内部ではコンソールGitを使用します。 美しいボタンをクリックすると、さまざまなトリッキーなパラメーターを持つGitコンソールコマンドが呼び出され、呼び出しの結果が再び美しい形式で表示されます。 すべてのクライアントがコンソールGitを使用するということは、すべてのクライアントがハードドライブ上のGitストレージの標準ファイル構造で動作することを意味します。 つまり、ある作業スタイルを使用して、あるクライアントで操作を実行し、別のクライアントで他の操作を実行することができます。
これで、Gitバージョン管理システムで使用される基本概念を学習しました。 メインチームの仕組みも同様です。 確かに、この記事を読んでいるときに、「どのボタンを押すべきか」という説明が欠けていました。 ただし、各Gitクライアントではこれは異なって見えるため、インターフェイスの説明からロジックの説明を分離する必要がありました。 クライアントの1つを選択して、そのユーザーインターフェイスを学習します。
頑張って!
初心者向けのGitのヒント-パート1
初心者向けのGitのヒント-パート2
初心者向けのGitのヒント-パート3