You made some commits and haven't uploaded them yet.
-
+
-
+
The server has some new commits which you haven't accepted yet.
-
+
-
+
Both you and the server have some new commits. Congratulations!
@@ -144,13 +78,7 @@ export function BranchCasesTable() {
section.
-
+
diff --git a/next/src/components/Tables/BranchTable.tsx b/next/src/components/Tables/BranchTable.tsx
index c7f0f4d..8631a19 100644
--- a/next/src/components/Tables/BranchTable.tsx
+++ b/next/src/components/Tables/BranchTable.tsx
@@ -1,4 +1,4 @@
-import Image from 'next/image'
+import { Inline } from '@/components/Inline'
export function BranchTable() {
return (
@@ -12,13 +12,7 @@ export function BranchTable() {
- {' '}
+ {' '}
Local branch
@@ -28,13 +22,7 @@ export function BranchTable() {
- {' '}
+ {' '}
Remote branch
@@ -45,13 +33,7 @@ export function BranchTable() {
- {' '}
+ {' '}
Tag
diff --git a/next/src/components/Tables/RecipeFollowTable.tsx b/next/src/components/Tables/RecipeFollowTable.tsx
index 1bd13ca..5e422e0 100644
--- a/next/src/components/Tables/RecipeFollowTable.tsx
+++ b/next/src/components/Tables/RecipeFollowTable.tsx
@@ -1,4 +1,4 @@
-import Image from 'next/image'
+import { Inline } from '@/components/Inline'
export function RecipeFollowTable() {
return (
@@ -14,53 +14,23 @@ export function RecipeFollowTable() {
-
+
-
+
-
+
-
+
-
+
Unclear
diff --git a/next/src/components/Tables/RecipeInferTable.tsx b/next/src/components/Tables/RecipeInferTable.tsx
index 913f3ce..31731ca 100644
--- a/next/src/components/Tables/RecipeInferTable.tsx
+++ b/next/src/components/Tables/RecipeInferTable.tsx
@@ -1,4 +1,4 @@
-import Image from 'next/image'
+import { Inline } from '@/components/Inline'
export function RecipeInferTable() {
return (
@@ -13,60 +13,24 @@ export function RecipeInferTable() {
-
+
-
+
-
+
-
+
-
+
-
+
diff --git a/next/src/components/Tables/TagsTable.tsx b/next/src/components/Tables/TagsTable.tsx
index 0f61e2e..963ee73 100644
--- a/next/src/components/Tables/TagsTable.tsx
+++ b/next/src/components/Tables/TagsTable.tsx
@@ -1,4 +1,4 @@
-import Image from 'next/image'
+import { Inline } from '@/components/Inline'
export function TagsTable() {
return (
@@ -14,43 +14,19 @@ export function TagsTable() {
Lightweight
-
+
-
+
Annotated
-
+
-
+
diff --git a/next/src/components/Video/Video.tsx b/next/src/components/Video/Video.tsx
index 44bd7d2..d941dab 100644
--- a/next/src/components/Video/Video.tsx
+++ b/next/src/components/Video/Video.tsx
@@ -2,10 +2,17 @@ import { CSSProperties, useEffect, useState } from 'react'
import { useVideoRef } from './useVideoRef'
import { throttle } from '../../lib/throttle'
import { PlayButton } from '../icons/PlayButton'
+import { assetPathFor, assetH, assetW } from '../../assets/assets.mjs'
type VideoProps = {
- poster: string
- source: string // must be mp4 video
+ mp4: string
+}
+
+function mp4_to_png(mp4: string): string {
+ if (!mp4.endsWith(".mp4")) {
+ throw Error("Expected to end with `.mp4`, was " + mp4)
+ }
+ return mp4.slice(0, mp4.length - "mp4".length) + "png"
}
export function Video(props: VideoProps) {
@@ -78,41 +85,47 @@ export function Video(props: VideoProps) {
}, [])
return (
-
- {showOverlay && (
-
-
+
+
+ {showOverlay && (
+
+
+
+ )}
+
+
- )}
-
-
-
-
+
+
)
}
diff --git a/next/src/components/Video/useVideoRef.tsx b/next/src/components/Video/useVideoRef.tsx
index 2b20e88..e900571 100644
--- a/next/src/components/Video/useVideoRef.tsx
+++ b/next/src/components/Video/useVideoRef.tsx
@@ -12,17 +12,16 @@ export function useVideoRef() {
setVideoBox(boundingBox)
}, [])
- function handleResize() {
+ const handleResize = useCallback(() => {
videoRefCallback(videoRef.current!)
- }
+ }, [videoRefCallback])
- // Recalculate the videoBox when the window is resized
useEffect(() => {
window.addEventListener('resize', handleResize)
return () => {
window.removeEventListener('resize', handleResize)
}
- }, [])
+ }, [handleResize])
return { videoBox, videoRef, videoRefCallback }
}
diff --git a/next/src/lib/throttle.ts b/next/src/lib/throttle.ts
index d93bcd5..577334f 100644
--- a/next/src/lib/throttle.ts
+++ b/next/src/lib/throttle.ts
@@ -4,35 +4,15 @@
// as much as it can, without ever going more than once per `wait` duration;
// but if you'd like to disable the execution on the leading edge, pass
// `{leading: false}`. To disable execution on the trailing edge, ditto.
-export function throttle(func: any , wait: number, options: {leading?: boolean, trailing?: boolean}) {
- var context: Function | null, args: any, result: any;
- var timeout: number | null = null;
- var previous = 0;
- if (!options) options = {};
- var later = function() {
- previous = options.leading === false ? 0 : Date.now();
- timeout = null;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- };
- return function(this: Function) {
- var now = Date.now();
- if (!previous && options.leading === false) previous = now;
- var remaining = wait - (now - previous);
- context = this;
- args = arguments;
- if (remaining <= 0 || remaining > wait) {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- previous = now;
- result = func.apply(context, args);
- if (!timeout) context = args = null;
- } else if (!timeout && options.trailing !== false) {
- timeout = window.setTimeout(later, remaining);
+export function throttle(callback: Function, limit: number) {
+ var waiting = false; // Initially, we're not waiting
+ return function throttled() { // We return a throttled function
+ if (!waiting) { // If we're not waiting
+ callback.apply(throttled, arguments); // Execute users function
+ waiting = true; // Prevent future invocations
+ setTimeout(function () { // After a period of time
+ waiting = false; // And allow future invocations
+ }, limit);
}
- return result;
- };
- };
-
\ No newline at end of file
+ }
+}
\ No newline at end of file
diff --git a/next/src/mdx/rehype.mjs b/next/src/mdx/rehype.mjs
index a57309a..0b45ff4 100644
--- a/next/src/mdx/rehype.mjs
+++ b/next/src/mdx/rehype.mjs
@@ -6,25 +6,35 @@ import { toString } from 'mdast-util-to-string'
import * as acorn from 'acorn'
import { slugifyWithCounter } from '@sindresorhus/slugify'
+// Move highlighter initialization outside the plugin
+let highlighter
+let theme
+
+// Initialize these in an async function
+async function initializeHighlighter() {
+ if (!highlighter) {
+ theme = await shiki.loadTheme('themes/github-light.json')
+ highlighter = await shiki.getHighlighter({ theme })
+ }
+ return highlighter
+}
+
function rehypeParseCodeBlocks() {
return (tree) => {
visit(tree, 'element', (node, _nodeIndex, parentNode) => {
if (node.tagName === 'code' && node.properties.className) {
parentNode.properties.language = node.properties.className[0]?.replace(
/^language-/,
- ''
+ '',
)
}
})
}
}
-let highlighter
-
function rehypeShiki() {
return async (tree) => {
- highlighter =
- highlighter ?? (await shiki.getHighlighter({ theme: 'css-variables' }))
+ const highlighter = await initializeHighlighter()
visit(tree, 'element', (node) => {
if (node.tagName === 'pre' && node.children[0]?.tagName === 'code') {
@@ -36,7 +46,7 @@ function rehypeShiki() {
if (node.properties.language) {
let tokens = highlighter.codeToThemedTokens(
textNode.value,
- node.properties.language
+ node.properties.language,
)
textNode.value = shiki.renderToHtml(tokens, {
diff --git a/next/src/mdx/remark.mjs b/next/src/mdx/remark.mjs
index e523464..a743508 100644
--- a/next/src/mdx/remark.mjs
+++ b/next/src/mdx/remark.mjs
@@ -1,4 +1,21 @@
import { mdxAnnotations } from 'mdx-annotations'
+import { visit } from 'unist-util-visit'
import remarkGfm from 'remark-gfm'
+import { assetPathFor, assetW, assetH } from '../assets/assets.mjs'
-export const remarkPlugins = [mdxAnnotations.remark, remarkGfm]
+export function remarkAssetPrefix() {
+ return (tree, file) => {
+ visit(tree, 'image', (node) => {
+ const assetKey = node.url
+ node.url = assetPathFor(assetKey)
+ node.data = {
+ hProperties: {
+ width: assetW(assetKey),
+ height: assetH(assetKey)
+ }
+ }
+ })
+ }
+}
+
+export const remarkPlugins = [mdxAnnotations.remark, remarkGfm, remarkAssetPrefix]
diff --git a/next/src/pages/branches/reflog.mdx b/next/src/pages/branches/reflog.mdx
index 35bbe03..669a940 100644
--- a/next/src/pages/branches/reflog.mdx
+++ b/next/src/pages/branches/reflog.mdx
@@ -11,10 +11,7 @@ If you lose the tip of a chain of commits in git, they are effectively "deleted"
3. Move the branch back by one commit, thus losing the "tip" that pointed to your life's work.
4. Mission accomplished!
-
+
## ... why am I using git, again?
@@ -30,10 +27,7 @@ Any commit that the process above can touch is reachable. Everything else is un
Not for long! Git has a mechanism called the reflog. **Every change to a branch is logged to the reflog**. This means that you can go into the reflog and see where a branch used to be. Let's use the reflog to get back your life's work.
-
+
This demonstrates that **if you committed it, you can get it back**. So commit often! Don't be embarrassed by unfinished or broken work - you can always make new, cleaner commits later (we'll show how in the [time-travel section](/time-travel)).
@@ -41,10 +35,7 @@ This demonstrates that **if you committed it, you can get it back**. So commit
There's a hiccup, which is that when you delete a branch, it also deletes that branch's reflog! There's an easy fix, which is `HEAD`. When you checkout a branch, it becomes the `HEAD`. Every new commit that you create is to the `HEAD` branch. And lucky for us, git keeps a reflog for `HEAD`, so that even if the branch we were using is now gone, we still have a record of those commits in `HEAD`.
-
+
## Do commits ever get *actually* deleted?
diff --git a/next/src/pages/branches/save-for-later.mdx b/next/src/pages/branches/save-for-later.mdx
index d944af0..4e72f89 100644
--- a/next/src/pages/branches/save-for-later.mdx
+++ b/next/src/pages/branches/save-for-later.mdx
@@ -1,14 +1,11 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Save work for later
It's common to make some changes in your working copy that end up looking like a dead end. It's tempting to just delete them and start over, but git makes it so easy to save them for later.
-
+
*Images by Mr. Gray, Morio, Terri Monahan, Rama, and Gmhofmann under various CCSA licenses, see [here for full credits](https://github.com/diffplug/gitfromscratch/blob/main/next/src/pages/branches/licenses.md).*
@@ -73,12 +70,7 @@ This gives you a fresh start, but you still have easy access to your work-in-pro
*Hint 1: To quickly save all files in the working copy, you can use the dropdown next to Commit.*
-
+
*Hint 2: If you're an experienced git user who already uses the "git stash" command, see the [departures from vanilla git](/epilogue/departures) section for more info.*
diff --git a/next/src/pages/branches/sticky-notes-and-paintbrushes.mdx b/next/src/pages/branches/sticky-notes-and-paintbrushes.mdx
index 72fc9c2..dbf951d 100644
--- a/next/src/pages/branches/sticky-notes-and-paintbrushes.mdx
+++ b/next/src/pages/branches/sticky-notes-and-paintbrushes.mdx
@@ -1,28 +1,18 @@
import { BranchTable } from '@/components/Tables/BranchTable'
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Sticky-notes and paintbrushes
You might think this is a branch:
-
+
...but a branch is actually _much_ simpler than that. **A branch is a name that points to a commit**. Commits have weird names - `518a9d2blahblahblah`. Branches let us use an easy-to-read name to mark a commit.
Technically, the correct term here is a git "ref", of which there are three types - local branch, remote branch, and tag. They all work the same way - a name that points to a commit - but they have different rules for how they can move. In the history table, they look like this:
-
+
@@ -30,10 +20,7 @@ Remote branches and tags are both primarily about team communication, so we'll w
Branches are easy to manipulate. Right-click a commit to create a new branch. You can drag-and-drop to move it around. Right-click the branch again to delete it.
-
+
We can use a branch in two ways:
@@ -48,10 +35,7 @@ Remember that a commit is a snapshot of every single file in your project folder
**The `HEAD` branch determines the starting point for the next commit.** When the next commit is made, the `HEAD` branch will automatically move so that it points to the new commit. Here's an example of what that looks like in practice:
-
+
Here's what happened in the video above:
@@ -74,9 +58,6 @@ As far as the files in your working copy are concerned, the only commits that ma
The tips section is useful for searching for branches and navigating history. When you hover the mouse over a branch, it will scroll the history window to show you where that branch is. When you stop hovering, it will scroll back to where you were. When you click a branch, it will scroll the history window there and stop.
-
+
Now that we can make commits, we'll look at how they can be [deleted and recovered](/branches/reflog).
diff --git a/next/src/pages/epilogue/departures.mdx b/next/src/pages/epilogue/departures.mdx
index 9e812f8..f0de208 100644
--- a/next/src/pages/epilogue/departures.mdx
+++ b/next/src/pages/epilogue/departures.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
# Departures from vanilla git
@@ -26,12 +26,7 @@ Here are just a few of the commands needed to manage this "index" mechanism:
In DiffPlug, we ignore the index entirely. If a file is checked in the commit window, then it will be put into the commit. Simple as that.
-
+
## No stash
@@ -39,12 +34,7 @@ It's common to have a situation where you've done a bunch of work that you'd lik
Vanilla git handles this with `git stash`. Because there are two places where changes can be - the working copy folder and the index - git has to do something pretty complicated. It makes one commit to save the index, and a second merge commit which saves the working copy and references the index commit.
-
+
It stores these as "refs/stash". If you call `git stash` a second time, it uses the reflog to keep the first stash around for a while.
diff --git a/next/src/pages/intro/clone.mdx b/next/src/pages/intro/clone.mdx
index 6f5e3b0..d91094e 100644
--- a/next/src/pages/intro/clone.mdx
+++ b/next/src/pages/intro/clone.mdx
@@ -14,10 +14,7 @@ Copying a repository from someone else's computer onto yours is called "cloning"
Go to wherever you'd like to put your clone, right-click it and then `Git -> Clone`. This will open a dialog where you can put the URL, and pick a destination folder on your computer. Once the download completes, you'll have your shiny new clone.
-
+
*Hint 1: You can't put a git repository inside another repository. If you don't see `Clone` as an option, you're probably inside an existing repository, and you need to move up to a higher folder.*
diff --git a/next/src/pages/intro/commit.mdx b/next/src/pages/intro/commit.mdx
index 08cd48a..3f2991f 100644
--- a/next/src/pages/intro/commit.mdx
+++ b/next/src/pages/intro/commit.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Make and edit a commit
@@ -7,54 +7,33 @@ import { Video } from '@/components/Video/Video'
Each row in the `History` table (the bottom of the screen) represents a commit. If you just created an empty repository, then you won't have much to look at yet, but you will soon! If you click a commit, you can see the names of files that were created, deleted, or changed between that commit and the previous commit.
-
+
If you click one of the changed files, you can see the actual contents of the file and how it changed.
-
+
You can also see metadata about who made the commit, when, and why.
-
+
If you double-click a commit, it will open the snapshot as a folder, so that you can see exactly what the project folder looked like when the snapshot was taken.
-
+
Now you're going to make your own commit. In the list of commits at the bottom, there is always a special row for something called the "working copy", often abbreviated "WC". **The working copy is a draft of the next commit you're going to make**. If you're looking at the working copy, then this button will say `Commit`. If it doesn't say `Commit`, then it will say `Go to WC`, and if you click it, it will take you to the working copy.
-
+
Once you're at the working copy, the `Changed files` section will show you which files you have modified in your project directory. To make sure that it is up-to-date, you can hit the refresh button. To make a commit, all you need to do is check the box for which files you'd like to commit, and type in a commit message which explains the reasoning behind your changes.
-
+
## Edit your commit
Pedants will tell you that it's impossible to edit a commit. Pedantically speaking that is true - however, you _can_ make a brand new commit with the same snapshot of files but a different commit message, which sure feels a lot like an edit. Right-click a commit and select `Edit metadata` to do this.
-
+
There are some rules about when you should and shouldn't change commits in this way, which luckily will turn out to be obvious when you understand git a little more. For now, pretend that you can only change your most recent commit. If you stick with us for a little longer then you'll understand fully when you can and can't "change" a commit.
@@ -62,11 +41,8 @@ There are some rules about when you should and shouldn't change commits in this
Every time you make a commit, it will be tagged with your name and email. That way when you share your commits, your colleagues will be able to know who to contact if they'd like to discuss a particular change. You only have to set your username once, and it will be set for all the commits you make to every repository.
-Click the command console , then select `Config library`. Once that is open, select `Git` from the tree at left and type in your name and email in the **Committer** box.
+Click the command console , then select `Config library`. Once that is open, select `Git` from the tree at left and type in your name and email in the **Committer** box.
-
+
Now that you know your way around commits, we can take a look at [branches](/branches/how-do-branches-work).
diff --git a/next/src/pages/intro/init.mdx b/next/src/pages/intro/init.mdx
index 4e058cd..0b8b258 100644
--- a/next/src/pages/intro/init.mdx
+++ b/next/src/pages/intro/init.mdx
@@ -1,14 +1,11 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Init a new repository
To take a folder and start tracking its changes, just right-click it and then `Git -> Create new`.
-
+
*Hint 1: You can't put a git repository inside another repository. If you don't see `Create new` as an option, you're probably inside an existing repository, and you need to move up to a higher folder.*
diff --git a/next/src/pages/intro/open-working-copy.mdx b/next/src/pages/intro/open-working-copy.mdx
index 17b306c..c272ec6 100644
--- a/next/src/pages/intro/open-working-copy.mdx
+++ b/next/src/pages/intro/open-working-copy.mdx
@@ -1,14 +1,11 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Open an existing working copy
-To open an existing working copy, drag the folder from your file explorer onto DiffPlug's icon. Then right-click it and select `Git -> History`.
+To open an existing working copy, drag the folder from your file explorer onto DiffPlug's icon. Then right-click it and select `Git -> History`.
-
+
_NOTE: Rather than dragging a file from your file explorer, you can use any of the methods described in the [DiffPlug quickstart](https://docs.diffplug.com/2.0.2/getting-started/quickstart/) to get the context-menu for a file._
diff --git a/next/src/pages/share/branches.mdx b/next/src/pages/share/branches.mdx
index 563b710..8b27eee 100644
--- a/next/src/pages/share/branches.mdx
+++ b/next/src/pages/share/branches.mdx
@@ -1,5 +1,5 @@
import { BranchCasesTable } from '@/components/Tables/BranchCasesTable'
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Collaborate on a moving target
@@ -15,10 +15,7 @@ You can use whatever convention you want, but the important thing is that publis
**Each time you download from a remote, your repository will have a remote branch placed wherever the equivalent branch is on the remote.** In the example below, the remote `dummy` is on the left. As its `test` branch is moved around, the move is reflected on the right each time that a download happens.
-
+
If you have a local branch with the same name as the remote branch, then DiffPlug can automatically help you keep these two in sync. If you right-click a branch (either the local branch or a remote branch), DiffPlug can show you what must be done to synchronize one with the other.
diff --git a/next/src/pages/share/remotes.mdx b/next/src/pages/share/remotes.mdx
index 68d5b69..337b20f 100644
--- a/next/src/pages/share/remotes.mdx
+++ b/next/src/pages/share/remotes.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Establish a connection
@@ -7,10 +7,7 @@ It is common for a team to have a central repository - a single "source of truth
In DiffPlug, you can see which servers you can communicate with by clicking the `Sync` tab and then looking at the `Remotes` section. Each server has its own button. If you click the button, you can see the details for that server.
-
+
If you just started a new project, then this section will be empty. If you cloned the project from a central server, then there's probably one remote named "origin". **A remote is just a URL with a nickname.** There are three kinds of URL:
@@ -31,18 +28,10 @@ You can have as many remotes as you'd like, but usually there will be just one c
In the following sections, we're going to show how you can synchronize your commits with a remote. While you're learning, it can be helpful to make a "dummy" remote that you can tinker with. To make a dummy remote, just copy-paste your whole git repository to a new folder. This will behave just like any other remote, but you can manipulate it directly to test various situations.
-
+
To add a normal `https` or `ssh/git` remote, just click the plus.
-
+
Now that we can connect to another git repository, we'll look at the easiest thing to share: [tags](../tags/tags.md).
diff --git a/next/src/pages/time-travel/cherry-pick-and-rebase.mdx b/next/src/pages/time-travel/cherry-pick-and-rebase.mdx
index 3592087..e7bf09f 100644
--- a/next/src/pages/time-travel/cherry-pick-and-rebase.mdx
+++ b/next/src/pages/time-travel/cherry-pick-and-rebase.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# Move and undo commits and chains of commits
@@ -7,18 +7,18 @@ There's a difference between the *content* of a commit and the *changes* between
## Moving the content in a commit
-If you want to copy some or all of the files in a commit into your working copy, right-click the commit and select `Apply content`. You can choose between:
+If you want to copy some or all of the files in a commit into your working copy, right-click the commit and select `Apply content`. You can choose between:
-- `all files into WC` copies every file from that commit into your working copy.
-- `some files into WC` copies individual files one at a time into your working copy.
+- `all files into WC` copies every file from that commit into your working copy.
+- `some files into WC` copies individual files one at a time into your working copy.
## Moving the changes in a commit
-When you click a commit, you see the changes that took place between that commit and its parent. To apply those same changes to your WC, all you have to do is right-click the commit, select `Apply delta`, and then one of its children:
+When you click a commit, you see the changes that took place between that commit and its parent. To apply those same changes to your WC, all you have to do is right-click the commit, select `Apply delta`, and then one of its children:
-- `and commit`
-- `all files into WC`
-- `some files into WC`
+- `and commit`
+- `all files into WC`
+- `some files into WC`
This will create a patch for the changes in this commit, and then apply it as either a new commit (`and commit`), or as an uncommitted change in the working copy (`all files into WC` and `some files into WC`). The distinction between `all files` and `some files` is whether you will apply every change, or just some of the changes.
@@ -34,79 +34,43 @@ Given that we can create a patch from a commit to its parent, we can use the exa
Let's say you have a series of commits like this:
-
+
And you would prefer that they looked like this:
-
+
Happens all the time. The `letters` branch is based off of the `common` commit, and you would rather it be based on the `3` commit.
-One way to do this is to right-click each commit, one at a time, and select `Apply delta`.
+One way to do this is to right-click each commit, one at a time, and select `Apply delta`.
-
+
-A faster way to accomplish this is the `rebase` command. Here's how it works:
+A faster way to accomplish this is the `rebase` command. Here's how it works:
- checkout the branch you want to move
- right-click the branch you'd like to change its base to
-- select `rebase`
+- select `rebase`
-
+
## Rebase onto origin/master
The scenario above happens especially often in a team setting - somebody else uploaded their changes before you did. Because it's so common, there's a shortcut for exactly this case:
-
+
But you need to be careful about rebasing branches which you have shared. When your branch moves to the new tip after a rebase, your old commits are [lost](/branches/reflog).
-
+
That's fine if you haven't shared those commits with anyone else, but it's not good if you already have. In the situation below, for example, the commits in `master` have already been published to `origin/sharedFeature`.
-
+
If you rebase `master`, there will be some duplicated commits!
-
+
[Merging](/time-travel/merge) is never bad, only use rebase when you haven't shared the commits with anyone else.
@@ -114,9 +78,6 @@ If you rebase `master`, there will be some duplicated commits!
The final result of rebasing one branch onto another is *exactly* the same as the final result of merging those two branches, except for the history.
-
+
The *only* difference is in the story that your history will tell. So whether we like it or not, every time we choose either to merge or to rebase, we have made a subjective, editorial decision about what kind of history will tell a better story. Which sets us up perfectly for our next topic: [rewriting history](/time-travel/rewrite-history).
diff --git a/next/src/pages/time-travel/merge.mdx b/next/src/pages/time-travel/merge.mdx
index 865fe58..6f4d618 100644
--- a/next/src/pages/time-travel/merge.mdx
+++ b/next/src/pages/time-travel/merge.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { Video } from '@/components/Video/Video'
# The merge
@@ -7,26 +7,17 @@ To merge two lines of commits back into a single line, you must create a merge c
To perform a merge, first we checkout the branch that we would consider to be "our" side of the merge. Then we right-click the other branch (which git calls "their" side), and select `Merge`.
-
+
Remember that the branch which we have checked out, `ABC`, is the paintbrush that we use to make new commits. That is why it moves to the newly created merge commit, while the other branch is unchanged. We can always undo a merge by just dragging our branch back to where it was.
-
+
## How do I look at a merge?
When you click a commit with one parent, you see a comparison between the snapshot of that commit and its parent. But what about when you click a commit with multiple parents? At first, you're looking at the difference between the commit and its first parent, but you can compare against other commits by clicking the `+`.
-
+
Answering the question "What changed in this commit?" is tricky for a merge commit - which is why you don't want to use them to make changes! **A merge commit should not introduce new changes; it should only combine the work of existing commits.** A merge commit which violates this rule is known as an "evil merge".
@@ -48,10 +39,7 @@ As we learned back when we [made our first commit](/intro/commit), **a commit is
Let's say we have only one branch, and we're doing some quick brainstorming. Each time we do something vaguely interesting, we make a commit. After a few such commits, we finally get to something useful. Because we made a commit each time we did something interesting, whether it was good or bad, we've recorded our entire thought process, but it's a little messy...
-
+
{/*
- Whale >> squirrel, delete squirrel
@@ -64,26 +52,17 @@ Let's say we have only one branch, and we're doing some quick brainstorming. Eac
We spent a lot of time making and coloring a squirrel, but in the end we removed it from our project entirely. If we're going to share this work with someone else, it might be wasteful for them to read up on all our squirrel thoughts, since all they really need to know is the blue whale. One way for us to clean up this work is to **squash it**.
-
+
Our new squashed commit has the exact same snapshot that the `Whale >> squirrel, delete squirrel` commit had. We just changed the commit's message and parents so that the history tells a more concise summary of our thought process.
The potential problem with this approach is that we've lost the history of our brainstorming. If we wanted to keep this history, while also summarizing our final result concisely, we can use a **summary merge**.
-
+
Let's compare the final result of the "squash" with the final result of the "summary merge".
-
+
There's a lot about these commits which are _exactly_ the same.
@@ -119,12 +98,7 @@ In the worst-case, a merge conflict will end up producing _four_ versions of the
The full commit history producing this situation might be complex, but if we focus on a single conflicted file, we can ignore all the intermediate changes and describe the relationships between the relevant versions in a simple diamond.
-
+
At this point, the tools have done everything they can to give you the context for the conflict, and it's your job to figure out what the working copy ought to be. Once you have made the working copy the way that you want, you declare to git "I have resolved this conflict, accept my gospel" and you can go on with your work.
diff --git a/next/src/pages/time-travel/patch.mdx b/next/src/pages/time-travel/patch.mdx
index cb59d19..9c6ad34 100644
--- a/next/src/pages/time-travel/patch.mdx
+++ b/next/src/pages/time-travel/patch.mdx
@@ -1,4 +1,4 @@
-import { Image } from '@/components/Image'
+import { Inline } from '@/components/Inline'
import { RecipeFollowTable } from '@/components/Tables/RecipeFollowTable'
import { RecipeInferTable } from '@/components/Tables/RecipeInferTable'
@@ -75,39 +75,19 @@ Earlier, we realized that any diff is a recipe that we can follow. **The defini
Let's try to merge these two branches.
-
+
Using the preconditions we just learned about, we can generate these patches for each side:
-
+
Because the patches don't touch the same files, their order doesn't matter. Whether we start with the dog,
-
+
or we start with the whale,
-
+
we get the exact same final result. This only works if the patches don't touch the same file, and it always works if the patches don't touch the same file.
@@ -115,21 +95,11 @@ we get the exact same final result. This only works if the patches don't touch
Let's say that instead, we have these branches:
-
+
Which gives us these patches:
-
+
There's no way to apply both patches, because once we have applied one, we have violated the preconditions for the other. If we can put a man on the moon, we should be able to fix this. Instead of treating `animals.zip` as an indivisible entity, we ought to be able to refer to its contents just like we refer to the contents of our project, right?
@@ -144,12 +114,7 @@ In order for our patches to share the zip file, we need to:
Then our patches could look like this:
-
+
Vanilla git treats zip files as indivisible, so it's not able to do this. But it is able to do this for text files.
@@ -159,12 +124,7 @@ Making patches to a tree of files is fairly easy because it's easy to identify a
Let's look at this scenario:
-
+
{/*
The Merry Versions of Vindsor
Act II, Scene 2
@@ -177,12 +137,7 @@ Git: Not a byte.
One way we could try to identify pieces is with line numbers. Let's try that:
-
+
Hmmm... relying on position alone is not very robust. Let's instead try using the content of the line above and below what we're trying to change.
diff --git a/next/src/pages/time-travel/rewrite-history.mdx b/next/src/pages/time-travel/rewrite-history.mdx
index 1d56e72..06b1385 100644
--- a/next/src/pages/time-travel/rewrite-history.mdx
+++ b/next/src/pages/time-travel/rewrite-history.mdx
@@ -12,10 +12,7 @@ We've touched on some of these techniques in passing before, but this is our cha
The simplest history-simplification is to simply squash two or more commits together. Ctrl-select the commits you want to squash, right-click, and select `Squash`.
-
+
## Rewrite
@@ -27,10 +24,7 @@ If you drag the working copy branch backwards to a point on its history, you are
This means that you have moved your project back in time, but you can easily see all the work you have done since then.
-
+
You now have two options, a summary merge or a full rewrite.
@@ -38,26 +32,17 @@ You now have two options, a summary merge or a full rewrite.
The summary merge keeps every single commit of your brainstorming, and supplements it with a summary of the final result. We discussed this technique in more detail in the [merge section](/time-travel/merge).
-
+
### Full rewrite
You can also pick and choose which commits to include or exclude, and in which order.
-
+
It is also possible to split a large commit into multiple smaller ones, or vice-versa.
-
+
## Durability is social