コンテンツにスキップ
GitTree

レッスン 21 · 歴史と統合

マージとリベース: グラフで選択する

同じ分岐の 2 つの同一のコピーからマージとリベースを実行し、2 つのグラフ、親、およびファイル ツリーを比較し、それらの間で決定する 1 つのルール、つまりすでにコミットを持っている人がいるかどうかを学びます。

このブラウザに進行状況が保存されました。

再生すると、YouTube からビデオが読み込まれます (プライバシー強化モード)。

英語ナレーション · English and Arabic 件のキャプション

動画ページを開くYouTubeで見る

何を学ぶか

  • 同一のコピーからマージとリベースを開始するため、比較は公平になります。
  • マージ コミットの 2 つの親と、リベースされたコミットの 1 つの新しい親を読み取ります。
  • 2 つのコピーが同じファイルで終了するにもかかわらず、異なる履歴が残る理由を説明します。
  • ルールは 1 つあり、他の人が持っていないコミットのみを書き換えます。

始める前に

レッスン 20 の分岐の 2 つの別々のコピー (gittree-merge と gittree-rebase という名前) が必要です。各コピーでは、ブランチ feature/signup-form は 1 つのコミット (S とします) を保持し、ブランチ updated-main は 1 つの異なるコミット (N とします) を保持します。どちらも同じコミット M から開始され、rescue/signup-before-rebase は S を指します。トピック ブランチはチェックアウトされており、ワーク ツリーはクリーンです。最初のコピーの結果から 2 番目のコピーを作成しないでください。

ここにあるものはすべてローカルであり、無料プランです (GitTree はサインインを求めます)。ホスティング アカウント、プロバイダー、インターネットはありません。すべての ID は架空のもの (example.com) であるため、このレッスンを実際のプロジェクト内で実行しないでください。

変更は、GitTree 内で行うか、ネイティブ Git コマンドを使用して行います。同じコピー内で両方を行うことはできません。後で結果を読むことは常に安全です。メニュー ラベルは、GitTree 2.0 独自の文字列から取得されます。ネイティブ コマンドは、使い捨てコピーの Git 2.43 で実行されました。 GitTree ステップは macOS、Windows、または Linux で実行されませんでした。アプリのショートカットでは、このページで Ctrl が記述されている macOS で Command を使用します。

概念と状態の効果

比較は、両方のコピーが同じ参照および同じファイルから開始される場合にのみ公平になります。最初にマージしてからその結果をリベースする場合は、別の質問をすることになります。つまり、リプレイの範囲内にマージ コミットが含まれるようになります。

Merge は両方の作業を維持します。これは、最初に S、次に N という 2 つの親を持つ 1 つの新しいコミット K を追加します。S と N は ID を保持します。

Rebase は N の上にコミットを再実行します。結果の S' には S と同じ変更が加えられていますが、新しい親があり、コミットの ID にはその親が含まれるため、S' には新しい ID が付けられます。古い S が生き残るのは、レスキュー ブランチがまだそれを指しているからです。

何も競合しない場合、両方のコピーは同じファイル ツリーで終了します。ツリーが等しいということは履歴が等しいということではありません。一方のグラフはひし形を維持し、もう一方のグラフは直線を維持し、コミット ID は異なります。

どちらが正しいかは好みの問題ではありません。他の人がすでにあなたのコミットを持っている場合、それらを再実行するとコピーが壊れるので、マージしてください。コミットがプライベートである場合、リベースは安全であり、チームがリベースを希望する場合は、直線的な履歴が得られます。どちらもコードを改善するものではありません。

各コピーでは、トピック ブランチのみが移動します。サーバー、updated-main、および元のメインには触れません。

正確なプロジェクトの状態を準備する

分岐を 1 つ作成し、それを 2 回コピーします。レッスン 18 で残したプロジェクトの別の通常のコピーから開始します (メインはマージ コミット M)。元の gittree-features はそのままにしておき、これをソース チェックアウトで実行しないでください。デモ ID は GitTree Demo、demo@example.com で、このリポジトリでのみ署名がオフになっています。

完全なファイル入力

以下のフェーズでのみ保存します。これらは、最後に改行を含む完全な UTF-8/LF 本文です。 Markdown フェンスは決して貼り付けないでください。変更されていない実行可能ファイルは、名前付き入力を継承します。別のバリアントのバージョンでオリジナルを上書きしてはなりません。

Index.html — サインアップ

ファイルの抜粋 · html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>GitTree Features — course demo</title>
  <link rel="stylesheet" href="styles.css">
</head>
<body>
  <header class="site-header">
    <a href="#main">GitTree Features</a>
  </header>
  <main id="main" tabindex="-1">
    <section class="hero" aria-labelledby="hero-title">
      <p class="eyebrow">GitTree Learn demo project</p>
      <h1 id="hero-title">See your work clearly.</h1>
      <p id="hero-copy">Choose one change, then check what Git saved.</p>
    </section>
    <section class="features" aria-labelledby="features-title">
      <h2 id="features-title">Follow your work</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>History</h3>
          <p>Read commits and branches together.</p>
        </article>
        <article class="feature-card">
          <h3>Changes</h3>
          <p>Review the exact content selected for a commit.</p>
        </article>
        <article class="feature-card">
          <h3>Recovery</h3>
          <p>Inspect the scope of a recovery point before using it.</p>
        </article>
      </div>
    </section>
    <section aria-labelledby="plans-title">
      <h2 id="plans-title">Choose the workflow you need</h2>
      <div class="cards">
        <article class="feature-card">
          <h3>Local Git</h3>
          <p>Local Git workflows work without signing in.</p>
        </article>
        <article class="feature-card">
          <h3>Connected workflows</h3>
          <p>Provider integrations and Nour require Pro or an applicable trial.</p>
        </article>
      </div>
    </section>
    <section aria-labelledby="signup-title">
      <h2 id="signup-title">Try the demo form</h2>
      <form id="signup-form" novalidate>
        <label for="demo-email">Demo email</label>
        <input id="demo-email" name="email" type="email" autocomplete="off" aria-describedby="signup-hint">
        <p id="signup-hint">Use a fictional example.com address. Nothing is sent.</p>
        <button type="submit">Check the address locally</button>
        <p id="signup-result" role="status"></p>
      </form>
    </section>
  </main>
  <footer><p>Built by a fictional team for GitTree Learn. Review one change at a time.</p></footer>
  <script type="module" src="site.js"></script>
</body>
</html>

docs/integration-note.md — DOC_MERGE

出力
# Integration review

This note was written on main while signup work was private.

GitTreeで

Command+Shift+P (Ubuntu では Ctrl+Shift+P) でパレットを開き、正確なコマンド名を入力して選択します。名前付きブランチに対するアクションには、そのブランチの右クリック メニューが使用されます。

  1. gittree-merge を開きます。次に、New Tab を選択し、その Recent リストから gittree-rebase を開きます。各タブにはフォルダー名が付いているので、2 つを区別できます。
  2. gittree-merge タブで、feature/signup-form をチェックアウトしたままにします。 updated-mainを右クリックして、Merge updated-main into feature/signup-formを選択します。
  3. Record it as で Always a merge commit を選択し、次に Merge を 1 回選択します。新しいコミットには 2 つの親があります。最初に S、次に N です。
  4. gittree-rebase タブに切り替えます。保存したときと同じように、まだ S と N にあります。マージコピーは使用しないでください。
  5. updated-main を右クリックして、Rebase feature/signup-form onto updated-main を選択します。 Options for this rebase を読み、両方のオプションをオフのままにして、Rebase feature/signup-form を 1 回選択します。
  6. 再生されたコミットを選択します。その親は N で、その ID は新しいです。古い S は依然として rescue/signup-before-rebase によって名前が付けられています。
  7. 各タブで Show Files → index.html と docs/integration-note.md を開きます。どちらのコピーでも同じページと同じメモです。その後、Back to Graph で戻ります。
  8. 2 つのグラフを比較し、結果を選択する前に、どのルールがこの分岐の選択を決定するかを判断します。両方のコピーをそのままにしておきます。

コース内のすべての通常のコミット: Summary は指定された件名、Description は空、オプション Amend Previous Commit、Skip Hooks、Add Signed-off-by、Different Author、Push After Commit、および Allow Empty Commit はオフのままです。このレッスンでは通常のコミットは行いません。

ターミナル内

レッスン 18 の結果の別のクリーン コピーで発散を構築します (アプリ内で実行し、ネイティブ コマンドとして記述された作業)。

Command · bash
git switch --create feature/signup-form

完全な SIGNUP ページを index.html として保存し、次のようにします。

Command · bash
git add -- index.html
git commit --quiet -m "feat: add the local signup demonstration"
git branch rescue/signup-before-rebase
BASE_SHA="$(git rev-parse HEAD~1)"
git switch --quiet --create updated-main "$BASE_SHA"

updated-main で完全な DOC_MERGE メモを docs/integration-note.md として保存し、次の操作を行います。

Command · bash
git add -- docs/integration-note.md
git commit --quiet -m "docs: add the integration review"
git switch --quiet feature/signup-form

BASE_SHA は、両方の行の成長元となるコミット M です。次に、この正確な状態 (cd .. && cp -R gittree-features gittree-merge && cp -R gittree-features gittree-rebase) から 2 つの独立したコピーを作成します。マージコピーでは次のようになります。

Command · bash
git merge --quiet --no-ff --no-edit updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --short

変更されていないリベース コピーでは次のようになります。

Command · bash
git rebase --quiet --no-autostash --no-update-refs --no-autosquash updated-main
git rev-list --parents -n 1 HEAD
git rev-parse 'HEAD^{tree}'
git status --short

git rev-list --parents -n 1 HEAD は、コミットの ID に続いてその親を出力します。マージ コピーには 3 つの ID、リベース コピーには 2 つの ID が表示されます。 2 つの HEAD^{tree} 行は同じ ID であり、git status --short は両方に何も出力しません。 2 つの HEAD コミット ID は異なります。あなたの ID は他の人の ID とは異なります。このページではなく、自分のページと比較してください。

トピックに独自のコミットがなく、updated-main がそのトピックの前にあるだけの場合、git merge はデフォルトで早送りし、マージ コミットを作成しません。それは、異なる入力と異なる結果です。意図的にそれを選択し、2 つの親のマージを偽装しないでください。

結果

Where you end: マージ コピーには、親 S および N を持つ新しいコミット K があります。リベース コピーには親 N を持つ S' があり、古い S はレスキュー ブランチによって保持されます。ファイル ツリーは同等で、両方のステータスはクリーンで、元のメイン、M、およびサーバーは変更されていません。

よくある間違い

  • 直線のグラフは、古いコミット ID が残っていることを意味すると仮定します。リベースでは常に新しいコミットが作成されます。
  • マージ結果からリベースを開始します。これは別の実験であり、リプレイにはマージ コミットが含まれる場合があります。
  • 2 つの HEAD ID を比較し、一致することを期待します。代わりに木を比較してください。
  • マージまたはリベースが完了した後に、マージまたはリベースを繰り返す。

何か問題が発生した場合

強制的に一致させるためにどちらの結果も破棄しないでください。ツリーが異なる場合は、開始参照、競合解決、および追加のコミットを比較し、保存された相違点から再度開始します。レスキュー ブランチはコミットされた履歴のみを保持します。コミットされていないファイルは保持されません。

理解度を確認してください

各質問に答えてから、その理由を読みましょう。 「必須」とマークされた質問は、レッスンの完了にカウントされます。

  1. 質問 1 / 6

    同じスタートから、1 つのコピーで updated-main を feature/signup-form にマージし、別のコピーで feature/signup-form を updated-main にリベースします。トピックの新しいヒント コミットの各コピーには親が何人いますか?

    答えを 1 つ選択してください。

  2. 質問 2 / 6

    マージとリベースが競合せずに完了すると、両方のコピーで同じになるのはどれですか?

    当てはまるものをすべて選択してください。

  3. 質問 3 / 6
    必須

    リベース後、元のトピックのコミット S はどうなりましたか?

    答えを 1 つ選択してください。

  4. 質問 4 / 6

    入力を変更します。トピックには独自のコミットがなく、updated-main がその前にあるだけです。デフォルトのモード「可能であれば早送り、そうでなければマージコミット」を使用してマージします。何が起こるのですか?

    答えを 1 つ選択してください。

  5. 質問 5 / 6
    必須

    同僚はすでに feature/signup-form をプルしており、それを基にして構築しています。 main の履歴を整理しておきたいと考えています。安全な選択とは何でしょうか?

    答えを 1 つ選択してください。

  6. 質問 6 / 6
    必須

    比較が公正であったことを示し、比較がどのように終わったかを示すリードバックはどれですか?

    当てはまるものをすべて選択してください。

6 個中 0 個が正解です

必須の質問に正しく答えると、レッスンを完了できます。

このブラウザで確認しました。

練習する

2 つの親リスト、2 つの HEAD ID、および 2 つのツリー ID を報告します。異なる HEAD ID の隣にあるツリー ID が等しいことが予期される結果である理由を説明してください。次に、トピックに独自のコミットがない場合にデフォルトのマージが何を行うかを、実行せずに予測します。

あなた自身の確認: サイトはあなたのコンピュータを認識できません。

レッスンを完了するには、必須の質問に正しく答え、実践的な演習を確認してください。

要約

  • 同じスタートでも、違う歴史。
  • 木が同じだからといって歴史が同じというわけではありません。
  • 他の人があなたのコミットを持っているときにマージします。プライベートなもののみをリベースします。

用語集の用語の紹介

リベース — 再ベース;リプレイ — إعادة تطبيق;レスキューブランチ — فرع حفظ.

ビデオトランスクリプト

ビデオのナレーションが次々と流れます。

トランスクリプトを表示する
  1. マージまたはリベース?同じ仕事でも辞められる 二つの異なる歴史。
  2. 両方を同じスタートから実行します point and compare.
  3. ブランチにはコミットが 1 つあります。 The updated branch has another.
  4. どちらも同じコミットから成長したものであるため、どちらも もう一方が含まれています。
  5. まず分岐を用意して2つ作ります 同一のコピー。
  6. 公平なテストには同じ参照とファイルが必要です in both copies.
  7. Here is the first copy.合併します これ。
  8. そしてこれが2枚目です。 We keep it リベースではそのままです。
  9. 「updated-main」を右クリックし、その「updateed-main」を選択します。 マージコマンド。
  10. [名前を付けて記録] で、[常にマージ] を選択します コミットします。
  11. 一度マージを選択し、実際のマージを待ちます result.
  12. 新しいコミットには 2 つの親があります。 commit、次に updated-main です。
  13. さて、2枚目です。 It still has the two オリジナルのコミット。
  14. [updated-main] を再度右クリックし、[更新済みメイン] を選択します。 今回はリベースします。
  15. ダイアログではブランチに名前を付け、 ターゲット。 Leave both options off.
  16. Rebase once. Git はコミットをリプレイします updated-main の先頭。
  17. 再生されたコミットには新しい親があるため、 新しいIDを取得します。
  18. 古いコミットは失われません: レスキュー ブランチはまだそれを指しています。
  19. Now compare the files.そのページは、 どちらのコピーでも同じです。
  20. 統合ノートも同様です。 Same files, 違う歴史。
  21. 2 つのグラフを見てください。ひし形と マージコミットと直線。
  22. では、どれを使用すればよいでしょうか? Ask who else あなたのコミットがあります。
  23. 他の人が持っている場合はマージします。 A rebase would 彼らの歴史を書き換える。
  24. コミットがプライベートの場合、リベースは 安全で直線が得られます。
  25. どちらもコードを改善するものではありません。ルール is about ownership.
  26. 今度はターミナルで証明してみます。 First, the 各チップの親。
  27. マージ コピーの 3 つの ID: コミット、 and its two parents.
  28. リベース コピーの 2 つの ID: コミット、 そしてその一方の親。
  29. 次に、ファイル ツリー: 1 つの ID、出力 2回。 Same files.
  30. ただし、2 つのコミット ID は異なります。 Equal 木々、さまざまな歴史。
  31. 入力を変更します。ブランチに次のものがあったとします。 独自のコミットはありません。
  32. デフォルトのマージは早送りされます。 マージコミットなし。
  33. 他の人が作成したブランチをリベースしないでください すでに持っています。
  34. ツリーが異なる場合は、開始時点を比較します。 refs first.
  35. 結果を削除して 2 つを強制しないでください。 一致します。
  36. 練習: 両親、ID、および あなた自身のコピーからの木。
  37. 次に、順序を変更し、まとめて、言い換えます。 ローカルコミット。