Skip to content
GitTree

Lesson 25 · History and integration

Apply selected commits with cherry-pick

Copy one teammate's fix onto your release branch without merging her whole branch, then check the new commit, its author, its files and what stayed behind.

Progress saved in this browser.

Playing loads the video from YouTube (privacy-enhanced mode).

English narration · English and Arabic captions

Open the video pageWatch on YouTube

What you will learn

  • Choose the one commit to copy, and see why its parent does not come along.
  • Predict the new commit's ID, author and committer.
  • Recognise a missing dependency or an already-applied change before you force anything.
  • Check the result against the source branch.

Before you start

Priya's branch priya/label holds two commits above a shared baseline B (the signup page). The first is an unrelated note, "docs: unrelated source note", that adds docs/temporary-review.md. The second is her fix, "fix: clarify the fictional email label", which changes the label in index.html. Your branch release/label starts from the same baseline B and has one commit of its own, "docs: record target review", which adds docs/integration-note.md. release/label is checked out and the work tree is clean. You want her fix on your branch, but not her note.

Everything is local and on the Free plan (GitTree asks you to sign in): no hosting account, no provider, no internet. Every identity is fictional (example.com). Never run this lesson in a real project.

Make the changes in GitTree or with the native Git commands, not both in the same copy. Reading the result is always safe. The menu labels come from GitTree 2.0's own strings and the native commands were run with Git 2.43 in disposable copies. The GitTree steps were not run on macOS, Windows or Linux.

Concept and state effects

Cherry-pick takes the change that one commit made, measured against its own parent, and applies it to the branch you are on as a new commit. It does not bring the parent, and it does not bring the commits before it. That is exactly why you can take Priya's fix and leave her note behind.

The source commit is not touched. The new commit has a new ID, because it has a new parent, but it keeps the original author and message. The committer, the person who made this commit, is you. The same change with the same message is still a different commit.

Dependencies still matter. The fix edits a line of the signup form, so the target branch must already have that form. If it does not, Git stops with a conflict. If the target already contains the same change, the pick would be empty and Git stops again. In both cases look at what the operation says; do not force an empty commit just to get past it.

Only the target branch moves. priya/label and everything on a server stay as they were. The new commit adds the label change to release/label and nothing else.

Prepare the exact project state

Start from a separate ordinary copy of the project as lesson 18 left it, and leave your original gittree-features untouched. Save SIGNUP as the baseline, then build the two branches. The bodies below are the baseline page (SIGNUP), the unrelated note (DOC_NOISE), the fixed page (SIGNUP_LABEL) and your own note (DOC_MERGE).

Complete file inputs

Save only at the phase named below. These are full UTF-8/LF bodies with a final newline; never paste Markdown fences. Unchanged runnable files inherit the named input. Versions in separate variants must not overwrite the original.

index.html — SIGNUP

File excerpt · 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/temporary-review.md — DOC_NOISE

Output
Temporary rehearsal note, deliberately dropped.

index.html — SIGNUP_LABEL

File excerpt · 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">Fictional email address</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

Output
# Integration review

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

In GitTree

Open the palette with Command+Shift+P (Ctrl+Shift+P on Ubuntu). Actions on a commit use that commit's right-click menu.

  1. Build the baseline and the two branches as the next section shows. Check out release/label and confirm that the work tree is clean.
  2. In the graph find Priya's commit "fix: clarify the fictional email label", not the note below it. Select it and read its details: one changed path, index.html, and its parent is the unrelated note.
  3. Right-click that commit and choose Cherry-Pick Commit. It applies at once to the branch you are on; there is no branch picker. The command is disabled on the commit that is already the current one.
  4. Wait for the real result. If an operation stops, use Resolve, Continue or Abort… on the banner instead of picking again.
  5. Select the new commit on release/label. Its ID differs from Priya's, the author is Priya Nair and the committer is GitTree Demo.
  6. Open index.html: it is SIGNUP_LABEL. docs/temporary-review.md is not there and your own docs/integration-note.md is. priya/label still names its old tip.
  7. Leave release/label clean. Do not push, and do not merge priya/label.

If you select two or more commits in the graph, the menu offers Cherry-Pick Commits and copies them in order. This lesson copies one.

For every ordinary commit in the course: Summary is the stated subject, Description is empty and the options Amend Previous Commit, Skip Hooks, Add Signed-off-by, Different Author, Push After Commit and Allow Empty Commit stay off.

In the terminal

In a separate copy of lesson 18's result, create the baseline branch before saving SIGNUP:

Command · bash
git switch --create label-base

Save SIGNUP as index.html, then:

Command · bash
git add -- index.html
git commit --quiet -m "feat: prepare the shared signup baseline"
BASE_SHA="$(git rev-parse HEAD)"
git switch --create priya/label

Save DOC_NOISE as docs/temporary-review.md, then:

Command · bash
git add -- docs/temporary-review.md
git commit --quiet -m "docs: unrelated source note"

Save SIGNUP_LABEL as index.html, then:

Command · bash
git add -- index.html
git -c user.name="Priya Nair" -c user.email=priya@example.com commit --quiet -m "fix: clarify the fictional email label"
PICK_SHA="$(git rev-parse HEAD)"
git switch --create release/label "$BASE_SHA"

Save DOC_MERGE as docs/integration-note.md, then:

Command · bash
git add -- docs/integration-note.md
git commit --quiet -m "docs: record target review"

Now pick the fix and read the result:

Command · bash
git cherry-pick "$PICK_SHA"
git log -1 --format='%s%n%an <%ae>%n%cn <%ce>'
git diff-tree --no-commit-id --name-only -r HEAD
git status --short
Output
fix: clarify the fictional email label
Priya Nair <priya@example.com>
GitTree Demo <demo@example.com>
index.html

The new commit's ID differs from PICK_SHA, index.html is SIGNUP_LABEL, docs/temporary-review.md is absent and the status is empty. Two variations to know, run in separate copies, never in the canonical one: git cherry-pick -x "$PICK_SHA" adds the line "(cherry picked from commit …)" to the new message, which helps when you pick across shared branches; and on a target that lacks the signup form the same command stops with a conflict on index.html, which you resolve (lesson 23) or leave with git cherry-pick --abort. If the target already has the change, Git stops again with an empty pick, and git cherry-pick --skip or --abort is the way out.

Result

Where you end: release/label has one new commit with Priya's fix, authored by Priya Nair and committed by GitTree Demo, with a new ID. The page has the clarified label, the unrelated note did not come along, priya/label and the server are unchanged and the work tree is clean.

Common mistakes

  • Thinking cherry-pick moves the commit. It copies the change; the original stays where it was.
  • Picking the wrong commit, the unrelated note instead of the fix.
  • Forcing an empty commit when the change is already on the branch.
  • Using cherry-pick to copy a whole feature, one commit at a time, instead of merging it.

If something goes wrong

If the pick stops, read the banner. Resolve and Continue finish it as in lesson 23; Abort… returns the branch to where it was. If the pick was a mistake after it finished, the new commit is only on release/label: undo it there, and the source branch was never touched.

Check your understanding

Answer each question, then read why. Questions marked “Required” count toward completing the lesson.

  1. Question 1 of 6

    What does cherry-pick copy?

    Choose one answer.

  2. Question 2 of 6

    After the pick, which of these are true about the new commit?

    Choose every answer that applies.

  3. Question 3 of 6
    Required

    Priya's fix sits on top of an unrelated note commit. You cherry-pick only the fix onto release/label. Is docs/temporary-review.md on release/label afterwards?

    Choose one answer.

  4. Question 4 of 6

    Change the input: release/label does not have the signup form that Priya's fix edits. What happens when you pick?

    Choose one answer.

  5. Question 5 of 6
    Required

    You pick a commit and Git stops with "The previous cherry-pick is now empty". The change is already on your branch. What do you do?

    Choose one answer.

  6. Question 6 of 6
    Required

    Which readbacks show the pick did what the lesson says?

    Choose every answer that applies.

0 of 6 correct

Answer the required questions correctly to complete the lesson.

Checked in this browser.

Practice

Report the new commit's ID, author and committer, its changed paths and whether docs/temporary-review.md exists. Then predict what happens if you pick the same commit again onto release/label.

Your own confirmation: the site cannot see your computer.

To complete the lesson, answer the required questions correctly and confirm the practical exercise.

Recap

  • Cherry-pick copies one commit's change as a new commit.
  • The parent and the commits before it stay behind.
  • Check dependencies and empty picks before forcing anything.

Glossary terms introduced

Cherry-pick — انتقاء; source commit — إيداع المصدر; target — الهدف; dependency — اعتماد.

Video transcript

The narration of the video, cue by cue.

Show the transcript
  1. Take one fix from another branch, and leave the rest.
  2. Cherry-pick copies the change one commit made, as a new commit here.
  3. The copy has a new ID, but keeps the author and the message.
  4. Build a baseline, Priya's branch with a note and a fix, and your release branch.
  5. Open the folder. The graph shows both branches from the same baseline.
  6. Priya's fix sits on top of an unrelated note. We want only the fix.
  7. Select the fix. One changed path: index.html.
  8. Make sure release label is current, and the work tree is clean.
  9. Right-click the fix, and choose Cherry-Pick Commit.
  10. There is no branch picker. It applies to the branch you are on.
  11. On the current commit itself, the command is disabled.
  12. Run it, and wait for the real result.
  13. A new commit sits on release label.
  14. Its ID differs from Priya's, because its parent is different.
  15. The author is still Priya. The committer is you.
  16. The page has the clarified label.
  17. The unrelated note did not come along. Your own note is still here.
  18. Priya's branch is exactly as it was.
  19. In the terminal, git log with a format shows the subject, author and committer.
  20. git diff-tree lists the paths this one commit changed.
  21. The status is empty. Nothing was left behind.
  22. With the x option, the message records where the pick came from.
  23. Pick the same commit again, and Git stops: the pick is empty.
  24. Change the input: the target has no signup form.
  25. The pick stops with a conflict. Resolve and continue, or abort.
  26. A change can depend on commits you did not take. Test the target.
  27. Abort puts the branch back. The source is never modified.
  28. Practice: report the new ID, author, committer and files.
  29. Next, set unfinished work aside safely with stash.