Skip to content

doc: add new git tutorial - #2248

Open
jvns wants to merge 2 commits into
gitgitgadget:masterfrom
jvns:git-tutorial
Open

jvns wants to merge 2 commits into
gitgitgadget:masterfrom
jvns:git-tutorial

Conversation

@jvns

@jvns jvns commented Oct 5, 2026 •

Copy link
Copy Markdown

So far we've gotten 112 comments from 30ish beta testers who have tried to learn Git for the first using this tutorial. Most of them were able to finish it successfully. By far the most common piece of feedback was that people want to learn more about collaboration and branching. I've written a draft of a tutorial on branching, but this is already quite a lot of words so definitely we can't cover it in this series.

I don't know if it's possible to get this merged quickly, but if it were I think it would be amazing since people are so eager for a tutorial on branching. If we spend a huge amount of time revising this I think there's a real risk I'll run out of funding before we have time to write about branching. Ideally I think it would be great if we could merge a "good enough" version and then have a way on the website for users to give feedback on it, so that we can later incorporate that feedback and iteratively make it better over time.

changes in v2:

  • check if "all versions above 2.0" is true
  • Mention that on Windows the tutorial will work best in Git Bash for and it might need adapting for PowerShell. (thanks to Ben)
  • Add a warning about how Git can dump you into vi and a little bit of information about how to write a longer commit message. I don't think we can use Pro Git here though since it's a bit outdated. (thanks to Ben)
  • Add Helped-by: Ben ...
  • Add output of "ls ~/.ssh/*.pub" (thanks to a test reader)
  • Suggest cat ~/.ssh/whatever.pub to make it clearer how to copy the contents of the file. One of the test readers said this was unclear as well. (thanks to Junio)
  • Add a short section on the importance of git status
  • A few other small phrasing fixes from test readers

non-changes in v2:

  • didn't use git config set since the tutorial claims to be compatible with Git 2.0
  • didn't change "folders" or "directories" for no specific reason

cc: "D. Ben Knoble" ben.knoble@gmail.com
cc: Tuomas Ahola taahol@utu.fi

Thanks to
vazdimet@gmail.com

 
Paula
Agavi
Ken Wells
Michael / Chgowiz
Ishmaeel

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There is an issue in commit ef6bac7:
doc: remove gittutorial

  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 7e001f0:
doc: Add new Git tutorial for beginners

  • Prefixed commit message must be in lower case
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit b88b987:
name email

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 2147e8b:
wip

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 3ce896a:
tell people to make empty directory

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 234110d:
master main augh

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit e4eba93:
bring a friend

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 72617f0:
more master main

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit e162372:
show un add

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 679adf2:
how to translate ssh url

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 53c4ac6:
bad security advice

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 7e35ef4:
bad security advice

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 5, 2026

Copy link
Copy Markdown

There are issues in commit 45e2fca:
auth key

  • Commit checks stopped - the message is too short
  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 6, 2026

Copy link
Copy Markdown

There is an issue in commit 503c90f:
doc: remove gittutorial

  • Commit not signed off

@gitgitgadget

gitgitgadget Bot commented Oct 6, 2026

Copy link
Copy Markdown

There are issues in commit 3cfae9b:
doc: Add new Git tutorial for beginners

  • Prefixed commit message must be in lower case
  • Commit not signed off

@jvns
jvns force-pushed the git-tutorial branch 3 times, most recently from 2598f8e to 41dca2e Compare October 6, 2026 19:25
@jvns

jvns commented Oct 6, 2026

Copy link
Copy Markdown
Author

/submit

@gitgitgadget

gitgitgadget Bot commented Oct 6, 2026

Copy link
Copy Markdown

Submitted as pull.2248.git.1791315422.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-2248/jvns/git-tutorial-v1

To fetch this version to local tag pr-2248/jvns/git-tutorial-v1:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-2248/jvns/git-tutorial-v1

@gitgitgadget

gitgitgadget Bot commented Oct 7, 2026

Copy link
Copy Markdown

"D. Ben Knoble" wrote on the Git mailing list (how to reply to this email):

On Tue, Oct 6, 2026 at 3:40 PM Julia Evans via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> This is the first draft of a tutorial which introduces Git in two parts:
>
> Part 1: Create an empty repo & make 2 commits (git init, git add, git
> commit, git status, git diff) Part 2: Push the repo to a remote host like
> GitHub or GitLab (git remote add, git push)
>
> So far we've gotten 112 comments from 22 beta testers who have tried to
> learn Git for the first using this tutorial. Most of them were able to
> finish it successfully. I'd like to avoid getting into the details of every
> single thing in the tutorial at this stage (we're still planning to do a
> second round of feedback with the beta testers, and the beginning especially
> will likely change)
>
> There are 2 questions I'd like feedback on since they both could affect the
> structure of the tutorial. I don't think either of these is a dealbreaker,
> since folks generally were able to finish the tutorial despite all these
> issues and said that they enjoyed it and learned a lot. But it would be
> great if there were an easy way to make the process less messy.
>
>
> question 1: create the repo on the command line, or in the forge?
> =================================================================

> c. Just try to get users to try to figure the right way in the
> GitLab/GitHub/etc UI to actually create an empty repository that it's
> possible to just push to. This is really hard because the UIs constantly
> change.
>
>
> current solution 1
> ==================
>
> Right now we're working on Option C since it seems least bad
>
>
> question 2: How to handle authentication
> ========================================

> current solution 2
> ==================
>
> Right now we're solving these by:
>
>  1. Using SSH
>  2. Explaining how to set up SSH in the easiest way possible (with
>     disclaimers to check your security team's policy if applicable since the
>     "easiest way" may not be the best)
>  3. Giving some instructions for how to translate an HTTPS URL to an SSH URL

Disclaimer, I haven't read the patches yet.

Both of these approaches sound like the right one to me. Assuming
we're suggesting up-to-date key algorithms for SSH, I think that
should be fine. (Memory says ECDSA and ED22519, I think? I'm not sure
about the differences, but my regularly-used keys are the latter and
my newest is the former.)

I happen to use a somewhat convoluted "new key for each host" policy
for myself, which ends up with lots of "Host <host> IdentifyFile
<key>" in ~/.ssh/config and "Include"d files. I think separate keys
per host is a good idea, but I certainly wouldn't want to foist that
mess on new users. OTOH, even leaving an admonition "you probably want
to set up one key per host later, so consider this just a starting
point" is how such starting points become prolific use practice ;)

So, idk on that front. Probably it's over-complicated to do that here,
and point to better guides (or worry about making one externally if
none exist), leaving the admonition in.

Thanks for letting me think aloud,
Ben

@gitgitgadget

gitgitgadget Bot commented Oct 7, 2026

Copy link
Copy Markdown

User "D. Ben Knoble" <ben.knoble@gmail.com> has been added to the cc: list.

@gitgitgadget

gitgitgadget Bot commented Oct 7, 2026

Copy link
Copy Markdown

"D. Ben Knoble" wrote on the Git mailing list (how to reply to this email) regarding 41dca2e:

On Tue, Oct 6, 2026 at 3:37 PM Julia Evans via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Julia Evans <julia@jvns.ca>
>
> This tutorial covers:
>
> 1. Creating an empty repo with `git init`
> 2. Making commits with `git add`, `git commit`, `git diff`, and
>    `git status`
> 3. Pushing to code to a Git host on the internet, including creating an
>    SSH key
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---
>  Documentation/gittutorial.adoc | 616 +++++++++++++++++++++++++++++++++
>  1 file changed, 616 insertions(+)
>  create mode 100644 Documentation/gittutorial.adoc
>
> diff --git a/Documentation/gittutorial.adoc b/Documentation/gittutorial.adoc
> new file mode 100644
> index 0000000000..617dbae096
> --- /dev/null
> +++ b/Documentation/gittutorial.adoc
> @@ -0,0 +1,616 @@
> +gittutorial(7)
> +==============
> +
> +NAME
> +----
> +gittutorial - Introduction to Git for beginners
> +
> +DESCRIPTION
> +-----------
> +
> +This tutorial explains how to import a project's code into Git, make
> +changes to it, and upload the project to the Internet.
> +
> +We'll show you how to use the commands `git commit`, `git add`,
> +`git diff`, `git status`, and `git push`.
> +
> +Command line vs GUI
> +-------------------
> +
> +Git is a command line program, but there are many excellent GUIs for
> +Git built by the community. For example, if you use an IDE to edit your
> +code, it might already have a built-in Git integration that you can use.
> +
> +In this tutorial, we'll give instructions for the command line version
> +of Git, but you can also follow along in a GUI. You can also do some
> +tasks in a GUI and some tasks on the command line. It's up to you.

Since we assume a *nix-ish environment, should we mention that this
tutorial works best on UNIX-like OSs, or in a Git-for-Windows Bash
environment, and may need adapting for folks using PowerShell, CMD, or
some other userspace (not a piece of jargon I would use here,
probably)? Or does that get covered incidentally by the installation
instructions?

I'm especially thinking of not confusing a user who sees something
different or doesn't have an "ls", "cd", etc. (Maybe my Windows
command line knowledge is shoddy, though, and those parts just kind of
work close enough for our purposes?)

> +
> +What we'll be doing
> +-------------------
> +
> +Git lets you take snapshots of your code, like a checkpoint in a video
> +game. In this tutorial we're going to explain a very basic Git
> +workflow, which is:
> +
> +1. Create an empty folder
> +2. Start using Git to manage the code in that folder
> +3. Create 2 files and tell Git to save a snapshot of them
> +4. Make changes to one of the files
> +5. Tell Git to take another snapshot
> +6. Repeat steps 4-5 any time you want to update your code

I'm very tempted to nitpick "folder" vs "directory," but I'm not sure
it's worth our time or that of the target audience :) Just note that,
while "git grep folder" finds way more hits than I was expecting, it
seems the primary use in our documentation is in reference to IMAP.

> +We'll also explain how to use Git to put your code on the Internet.
> +
> +Step 1: Make sure Git is installed
> +----------------------------------
> +
> +To do this tutorial, you'll need:
> +
> +1. Git to be installed. You might already have it installed,
> +   and if not there are directions at https://git-scm.com/install/
> +2. A folder on your computer with code that you want to start managing
> +   with Git.
> +
> +You can check if Git is installed by running this in your terminal:
> +
> +------------------------------------------------
> +$ git --version
> +------------------------------------------------
> +
> +[[step_2]]
> +Step 2: Introduce yourself to Git
> +---------------------------------
> +
> +The first time you use Git on a computer, it's a good idea to tell Git
> +your name and public email address. If you don't, you'll get a lot of
> +warnings from Git. To do this, run:
> +
> +------------------------------------------------
> +$ git config --global user.name "Namey McName"
> +$ git config --global user.email you@example.com
> +------------------------------------------------
> +
> +The name and email is so that other people you're collaborating with can
> +know who made the changes. You can set them to anything you want.
> +
> +To check if the name and email have been set, you can run these
> +commands:
> +
> +------------------------------------------------
> +$ git config user.name
> +$ git config user.email
> +------------------------------------------------

Ought we recommend the newer forms (git config set, git config get)?
Or is the idea to remain compatible with older versions, such as the
2.32 I happen to have in /usr/bin on unsupported macOS 12.7.6 from
very old (?) XCode?

> +
> +Set your default branch name to `main`, by running this command.
> +Git is going to change its default branch name to `main` soon, so this
> +sets you up well for the future.
> +
> +------------------------------------------------
> +$ git config --global init.defaultBranch main
> +------------------------------------------------
> +
> +If there's no output, then it succeeded.
> +
> +Step 3: Create an empty folder and 2 files
> +------------------------------------------
> +
> +In your terminal, create an empty folder and change directories into it.
> +Later on you could follow the same steps in this tutorial to take an
> +existing project and start managing it with Git, but we're going to use
> +an empty project so that everyone following this tutorial has the exact
> +same files.
> +
> +For example, run these commands to make a folder called `myproject`
> +
> +------------------------------------------------
> +$ mkdir myproject
> +$ cd myproject
> +------------------------------------------------

I don't know, and I'll probably bias towards what you've already
written over asking for changes, but: does it make things any easier
to read and follow along with if we "git init myproject" instead?
Perhaps this version plants the seed that it's not too late to start
tracking any existing project, though, which is valuable :)

I wonder if you had some rationale for choosing this particular
sequence? Just curious, now.

> +Create 2 files in this directory, so we have something to work with.
> +
> +Make a file called README.md, with these contents:
> +
> +------------------------------------------------
> +We're doing a Git tutorial!
> +We need 2 lines in this file so here's a second one
> +------------------------------------------------
> +
> +And a file called `hello.py`, with these contents:
> +
> +------------------------------------------------
> +print("hello world")
> +------------------------------------------------
> +
> +Save the two files and keep them open in your text editor so you can
> +easily edit them later. The exact contents aren't too important, but
> +we'll use those contents in the example output later.
> +
> +You can check that the files are in the right place by running `ls`,
> +like this:
> +
> +
> +------------------------------------------------
> +$ ls
> +------------------------------------------------
> +
> +The output should be like this:
> +
> +------------------------------------------------
> +hello.py
> +README.md
> +------------------------------------------------
> +
> +Step 4: Create a Git repository
> +-------------------------------
> +
> +A Git repository is a folder which stores snapshots. It's usually a
> +hidden folder called `.git`. Every time you take a snapshot, Git stores
> +a copy of the contents of every file you're tracking.
> +
> +This might feel unbelievable, but Git uses compression so you can easily
> +store tens of thousands of snapshots without using too much disk space.
> +
> +You can create a Git repository for any folder in your computer by
> +running the command `git init`.
> +
> +Run `git init` in the folder you just created, like this:
> +
> +------------------------------------------------
> +$ git init
> +------------------------------------------------
> +
> +Git will reply:
> +
> +------------------------------------------------
> +Initialized empty Git repository in .git/
> +------------------------------------------------
> +
> +You might notice a new hidden folder was created, named `.git`.
> +
> +Step 5: Take your first snapshot
> +--------------------------------
> +
> +Next, we're going to take a snapshot of all the files in the directory
> +and tell Git to store them. Taking a snapshot in Git is a two step
> +process: first you need to run `git add` and then `git commit`.
> +
> +The reason it's a two step process is that sometimes you might not
> +actually want Git to store a snapshot of _all_ the files in a folder.
> +For example, if you have a file full of private personal information
> +called `personal.csv`, and a Python script called `process_data.py`, you
> +might want Git to keep a snapshot of the Python script but not the
> +private data.
> +
> +For now, we're going to store a snapshot of every file in your folder,
> +as well as in every subfolder.
> +
> +The first step of creating a snapshot is to tell Git which files you
> +want to include in the next snapshot using `git add`. To tell Git
> +"include all files", run this command:
> +
> +------------------------------------------------
> +$ git add .
> +------------------------------------------------
> +
> +Next you can create the snapshot using the `git commit` command, like
> +this. The `-m` flag stands for "message", and it lets you set a reminder
> +for your future self of what you were doing. The message ("Initial
> +commit" in this example) can say anything you want.
> +
> +------------------------------------------------
> +$ git commit -m "Initial commit"
> +------------------------------------------------
> +
> +You've now stored the first version of your project in Git! From now on
> +we're going to use the word "commit" instead of "snapshot", since that's
> +the term Git uses.

I know we want to limit scope… but I would love to not accidentally
encourage more use of "-m" for short (often useless?) messages.
Unfortunately, that drags in the can of worms that is editor
configuration. At least we can maybe point to
https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_editor
and https://git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Setup-and-Config#ch_core_editor
? idk.

> +
> +Step 6: Make a change
> +---------------------
> +
> +Now, let's learn how to make a change to a file and review the change you made.
> +In this example, we'll update the file `README.md`, but you can edit a
> +different file.
> +
> +First open `README.md` in your favourite text editor, make a tiny or
> +silly change, and save it.
> +
> +Next, in the terminal, run the command `git status` to get a summary of
> +what you changed since the last Git commit.
> +
> +------------------------------------------------
> +$ git status
> +------------------------------------------------
> +
> +The output will look something like this:
> +
> +------------------------------------------------
> +On branch main
> +
> +Changes not staged for commit:
> +  (use "git add <file>..." to update what will be committed)
> +  (use "git restore <file>..." to discard changes in working directory)
> +        modified:   README.md
> +------------------------------------------------
> +
> +This output says that we've changed `README.md` since the last time
> +we committed.
> +
> +Next, if you want to see the details of how you've changed `README.md`,
> +you can run `git diff`.
> +
> +------------------------------------------------
> +$ git diff
> +------------------------------------------------
> +
> +The output will look something like this:
> +
> +------------------------------------------------
> +diff --git a/README.md b/README.md
> +index 7ebaecb3..5a4ff712 100644
> +--- a/README.md
> ++++ b/README.md
> +@@ -1,2 +1,2 @@
> + Here are some Python scripts!
> ++I hope you like them.
> +------------------------------------------------
> +
> +This output says that we added one line, saying "I hope you like them.".
> +By default Git will show the lines you removed in red, and the lines you
> +added in green.

I would perhaps prefer to focus on the leading sigils (-, +) than the
color, if only because colorblindness can lead to all sorts of
situations with different color setups in the terminal's palette or
even (probably not our target audience) Git configuration. We could
probably mention that Git shows added and removed lines in *different*
colors without being too concerned with which colors those are? (That
avoids having to twist our words like "your terminal palette's green
and red" or w/e.)

> +
> +Step 7: Make another commit (easy way)
> +--------------------------------------
> +
> +Now let's tell Git to save the new version of `README.md` by making
> +another commit! To tell Git to snapshot all files that Git is tracking
> +and commit them, run this command:
> +
> +------------------------------------------------
> +$ git commit -am "Update README"
> +------------------------------------------------
> +
> +This is similar to the two step process in Step 4 where we used `git
> +add` and `git commit` to make a commit, but with a shortcut that lets
> +you do both in just one command. The `-a` stands for "all".
> +
> +Step 7b: Make another commit (longer way)
> +-----------------------------------------
> +
> +`git commit -am` is a fast way to snapshot all the files that Git is
> +tracking. But if you want Git to ignore changes to certain files, you
> +can instead do a 2-step process like in Step 4 where first you run `git
> +add` for every file that's been changed and that you want to include in
> +the next commit, like this:
> +
> +------------------------------------------------
> +$ git add README.md
> +------------------------------------------------
> +
> +and then run `git commit` (without the `-a`), like this:
> +
> +------------------------------------------------
> +$ git commit -m "Update README"
> +------------------------------------------------
> +
> +Step 8: Make a change and throw it away
> +---------------------------------------
> +
> +One of the most useful things about Git is that it lets you safely
> +experiment: you never need to be scared to change your code because you
> +can always go back to the old version.
> +
> +Before starting to experiment, run `git status` to check the current
> +state of your Git repository:
> +
> +------------------------------------------------
> +$ git status
> +On branch main
> +
> +nothing to commit, working tree clean
> +------------------------------------------------
> +
> +This "working tree clean" message means that there haven't been any
> +changes since your last commit.
> +
> +Now make a change to your code, and run `git status` again. Like last
> +time, you should see a message like this:
> +
> +------------------------------------------------
> +$ git status
> +On branch main
> +
> +Changes not staged for commit:
> +  (use "git add <file>..." to update what will be committed)
> +  (use "git restore <file>..." to discard changes in working directory)
> +        modified:   README.md
> +------------------------------------------------
> +
> +This tells us that `README.md` has been changed since the last commit.
> +But we don't actually want this change, so let's undo it! We can restore
> +`README.md` back to how it was at the most recent commit using the `git
> +restore` command.
> +
> +**WARNING**: `git restore` can't be reversed! Any time you run it it's
> +important to be absolutely sure that you're okay with throwing away your
> +changes since the last commit.
> +
> +------------------------------------------------
> +$ git restore README.md
> +------------------------------------------------
> +
> +Now open `README.md` again. You should see that your changes have been undone.
> +
> +You can stop here!
> +------------------
> +
> +The commands we've learned so far (`git init`, `git add`, `git commit`,
> +`git diff`, `git status`, and `git restore`) are enough to get a lot out
> +of Git on their own.
> +
> +With these commands, you can keep copies of past versions of your code
> +on your computer and safely experiment with big changes to your code.
> +
> +When using Git this way, all of your code just lives on your computer.
> +But if you want to put your code on the Internet so that other people
> +can use it or back it up, then you'll need to learn about one more
> +command: `git push`.
> +
> +The rest of this tutorial is about how to upload your code to a Git
> +repository on the Internet. The high level process is:
> +
> +1. Create an account on the Git host
> +2. Configure Git so that it can login to the Git host to make changes
> +3. Run `git push origin main` to upload your code
> +
> +Navigating the Git host's UI can be tricky, and it's hard for us to
> +give you exact directions because the UIs change a lot.
> +
> +Step 9: Create an account on a Git host
> +---------------------------------------
> +
> +To put your code on the Internet, you need it to be hosted somewhere.
> +The easiest way to do this is to sign up with a Git host. There's a list
> +of Git hosts (many of them offer free accounts) at
> +https://git-scm.com/tools/hosting. GitHub and GitLab are two popular hosts.
> +
> +If you're comfortable running a server, there are other ways to host
> +a Git repository on the internet, like connecting through SSH or open
> +source Git forge software to your server.
> +
> +Step 10: Create an SSH key (if needed)
> +-------------------------------------
> +
> +For Git to upload changes to another Git repository, it needs a way to
> +login to that repository. One of the most popular ways to do this is
> +with an SSH key.
> +
> +If you don't already have an SSH key, you'll need to create one. On Mac
> +or Linux, you can check if you already have an SSH key by running:
> +
> +-------------------------------------------
> +$ ls ~/.ssh/*.pub
> +-------------------------------------------
> +
> +If you don't already have an SSH key, run:
> +
> +-------------------------------------------
> +$ ssh-keygen
> +-------------------------------------------
> +
> +`ssh-keygen` will ask you for some details.
> +The easiest way to do this is to just press Enter at every prompt until
> +it's done.
> +
> +NOTE: All of the advice about how to use SSH in this tutorial is aimed
> +at getting it to work as quickly as possible. Setting up SSH in a secure
> +way is very far outside the scope of this tutorial. If you have a
> +security team in your organization, they might have very different
> +opinions about the appropriate way to configure authentication with Git.
> +
> +Step 11: Tell the Git host your SSH public key
> +----------------------------------------------
> +
> +First, find your SSH key like this (on Mac or Linux):
> +
> +-------------------------------------------
> +$ ls ~/.ssh/*.pub
> +-------------------------------------------
> +
> +That will output something like
> +
> +-------------------------------------------
> +/home/alice/.ssh/id_ed25519.pub
> +-------------------------------------------
> +
> +Copy the contents of that file to your clipboard. It's important that
> +the filename ends in `.pub` ("pub" stands for "public").
> +
> +Then login to your account on the Git host you chose and paste the SSH
> +key into the appropriate place. Depending on the Git host, it's likely
> +under "SSH keys" in your settings. If it asks you what type of SSH key,
> +look for something like "Authentication Key".
> +
> +Once you've done this, you're done! Git will automatically use your SSH
> +key to try to connect.
> +
> +Step 12: Create an empty Git repository on the Git host
> +-------------------------------------------------------
> +
> +Go to the Git host's website and create a new Git repository.
> +
> +**WARNING**: If you create a public repository and push your repository
> +to it, then your name and email address, as well as the contents of
> +any files you committed and every previous version of those files, will
> +be on the public internet. Some Git hosts have the option to create
> +a private repository instead, to keep your information private.
> +
> +Step 13: Find the address of the repository
> +-------------------------------------------
> +
> +Now, find the address of the repository on your Git host. It should look
> +something like this:
> +
> +-------------------------------------------
> +git@git.example.com:username/repo.git
> +-------------------------------------------
> +
> +(where `example.com`, `username` and `repo` will be replaced with the
> +actual values).
> +
> +If you can only find an address starting with `https://`, then
> +you can often translate it to the SSH format by replacing `https://`
> +with `git@` and replacing the `/` after the domain name with an `:`.
> +Here's how:
> +
> +-------------------------------------------
> +https://git.example.com/username/repo
> +^^^^^^^^               ^
> +replace with "git@"    replace with ":"
> +-------------------------------------------

This is, of course, forge- and remote- dependent :) but I think it's
*probably* ok for the tutorial.

When you mentioned HTTPS-to-SSH translation, I was thinking of the
config-based URL rewrite mechanism, aha! I definitely don't think we
should go there ;)

> +
> +Step 14: push your changes
> +--------------------------
> +
> +Finally, we're ready to send the information in your local Git repository
> +to the one on the internet!
> +
> +First, tell Git about the other repository by running `git remote add`
> +in your terminal
> +(replace `git@example.com:username/repo.git` with the actual address):
> +
> +-------------------------------------------
> +$ git remote add origin git@example.com:username/repo.git
> +-------------------------------------------
> +
> +This tells Git to save the URL `git@example.com:username/repo.git` in
> +your Git repository's configuration under the name `origin`, so that you
> +can use it later. If you make a mistake while doing this, you can run
> +`git remote remove origin` and try again.
> +
> +Then tell Git to send the information, with `git push`
> +(if this doesn't work, read the "Troubleshooting `git push`" section for advice!):
> +
> +-------------------------------------------
> +$ git push -u origin main
> +-------------------------------------------
> +
> +`origin` refers to the URL we just added (`git@example.com:username/repo.git`),
> +and `main` is the name of your current Git branch. You can use any name
> +(not just `origin`), but using `origin` often makes things easier
> +because it's the default for `git push` and `git pull`.
> +We haven't covered branches yet, but `main` is the default branch name.

I'm not sure if we should recommend "-u" without being able to explain
what it does, and… well… you and I have discussed how that's difficult
:)

Doesn't the tutorial's recipe of always using "git push origin main"
work just fine? And if we later introduce pull and other
branch-/remote-stuff that cares about upstreams, we can mention this
shorthand then?

> +
> +Any time you want to set up a new repository, you can repeat steps
> +11-13, with one exception: you only need to pass `-u` the first time
> +you push. Afterwards you can just run the command:
> +
> +-------------------------------------------
> +$ git push origin main
> +-------------------------------------------
> +
> +It should output something like this:
> +
> +-------------------------------------------
> +To example.com:example_username/example
> + * [new branch]        main -> main
> +-------------------------------------------
> +
> +Troubleshooting `git push`
> +--------------------------
> +
> +There are 3 main errors you might run into when running `git push origin main`.
> +Getting errors when running `git push` is actually a big part of using
> +Git, so congratulations! If you get to this part of the tutorial, you
> +get a little bonus experience in debugging.
> +
> +Here's a guide to why they're happening and how to fix them.
> +
> +**Problem 1**: You pushed to `main`, but your branch actually isn't called `main`
> +
> +Here's the error:
> +```
> +$ git push origin main
> +error: src refspec main does not match any
> +```
> +
> +This might happen if you didn't set `init.defaultBranch` to `main` in
> +<<step_2,Step 2>>.
> +
> +If you want to check the name of your current branch, you can run `git
> +status`. For example, in this output, the current branch is "master".
> +
> +-------------------------------------------
> +$ git status
> +On branch master
> +
> +...
> +-------------------------------------------
> +
> +To push your branch, you have a few options:
> +
> +* rename your branch to `main`, by running `git branch -m main`
> +  and then run `git push origin main`
> +* run `git push origin master`
> +  (where `master` is the name of your actual current branch)
> +
> +**Problem 2: SSH error**
> +
> +Here's the error:
> +
> +-----
> +$ git push origin main
> +The authenticity of host 'github.com (140.82.116.3)' can't be established.
> +ED25519 key fingerprint is: SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
> +This key is not known by any other names.
> +Are you sure you want to continue connecting (yes/no/[fingerprint])?
> +-----
> +
> +Git uses SSH to connect during `git push`, and this message happens when
> +SSH connects to a new site that you haven't connected to before.
> +
> +The easiest way to handle this is to type "yes" and press Enter.
> +
> +**Problem 3: the repository already exists**
> +
> +Here's the error:
> +
> +---------------------
> +$ git push origin main
> +! [rejected]        main -> main (fetch first)
> +error: failed to push some refs to 'example.com:example/example.git'
> +hint: Updates were rejected because the remote contains work that you do not
> +hint: have locally.
> +---------------------
> +
> +If you see an error like this, it means that when you created the
> +repository on your Git host, it created a repository with a file in it
> +to try to help you out. (that's the "work that you do not have locally"
> +in the error message)
> +
> +You can fix this either by deleting the repository and recreating it, or
> +by running:
> +
> +---------------------
> +$ git push --force origin main
> +---------------------
> +
> +**WARNING**: In general it's quite dangerous to use `--force` because
> +it can erase work on the online repository in a way that's difficult to
> +recover. But if you know for sure that you just created the repository 2
> +minutes ago and there's nothing in it, then it's okay.
> +
> +MORE USEFUL GIT COMMANDS
> +------------------------
> +
> +* To tell Git to "un-add" a file that you added by accident, run
> +  `git rm --cached FILENAME`
> +
> +SEE ALSO
> +--------
> +linkgit:git-help[1],
> +
> +GIT
> +---
> +Part of the linkgit:git[1] suite
> --
> gitgitgadget

Overall I think this is excellent (and I wish bottom-post replies
encouraged saying this up front, hm).

Thanks!

-- 
D. Ben Knoble

@gitgitgadget

gitgitgadget Bot commented Oct 13, 2026

Copy link
Copy Markdown

The pull request has 33 commits. The max allowed is 30. Please split the patch series into multiple pull requests. Also consider squashing related commits.

The next commit replaces it with a new tutorial.

Do this as a remove/add instead of just replacing the file in a single
commit to make the patches easier to read on the mailing list, since the
existing content isn't being reused.

Signed-off-by: Julia Evans <julia@jvns.ca>
@jvns
jvns force-pushed the git-tutorial branch 2 times, most recently from 57ba3c7 to d6cd912 Compare October 19, 2026 14:15
@jvns jvns changed the title WIP: doc: add new git tutorial doc: add new git tutorial Oct 19, 2026
Introduce Git in two parts:

Steps 1-7: Create an empty repo & make 2 commits (`git init`,
`git add`, `git commit`, `git status`, `git diff`)
Steps 8-12: Push the repo to a remote host like GitHub or GitLab
(`git remote add`, `git push`)

Some design choices:

- Introduce a much smaller set of commands than the old tutorial, to
  keep the tutorial quick (doable in an hour). Some users found it to be
  very fast and some wanted to stop early (after step 7) so this seems
  to be a good balance.
- Have users start with an empty repository instead of an existing
  project, because many of the testers did not have an existing project
  to test, or were scared of using an existing project.
- Add a troubleshooting section, since in the testing some users got
  extremely stuck (for 4+ hours) on minor issues like needing to say
  "yes" when SSHing to a new host.
- Don't explain branches, because explaining branches and collaboration
  is complicated and deserves its own tutorial. Instead just tell users
  we're not going to explain them in this document.
- Tell users to set their default branch to `main`, because many Git
  hosts use it as their default branch and it really simplifies things.
- Keep it as vendor neutral as possible, while acknowledging the reality
  that Git hosting services like GitHub, GitLab, etc are extremely
  popular. Do this by creating the repo locally and then optionally
  pushing it later.
- Use SSH for authentication, explaining how to set up SSH in the
  easiest way possible (with disclaimers to check your security team's
  policy if applicable since the "easiest way" may not be the best), and
  giving some instructions for how to translate an HTTPS URL to an SSH
  URL.

At least 20 people have successfully completed it, and feedback was
incorporated from problems the testers ran into.

Co-authored-by: Marie Claire LeBlanc Flanagan <hello@marieflanagan.com>
Signed-off-by: Marie Claire LeBlanc Flanagan <hello@marieflanagan.com>
Signed-off-by: Julia Evans <julia@jvns.ca>
@jvns

jvns commented Oct 19, 2026

Copy link
Copy Markdown
Author

/submit

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

Submitted as pull.2248.v2.git.1792421748.gitgitgadget@gmail.com

To fetch this version into FETCH_HEAD:

git fetch https://github.com/gitgitgadget/git/ pr-2248/jvns/git-tutorial-v2

To fetch this version to local tag pr-2248/jvns/git-tutorial-v2:

git fetch --no-tags https://github.com/gitgitgadget/git/ tag pr-2248/jvns/git-tutorial-v2

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

"Julia Evans" wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

On Wed, Oct 7, 2026, at 3:48 PM, D. Ben Knoble wrote:
> On Tue, Oct 6, 2026 at 3:37 PM Julia Evans via GitGitGadget
> <gitgitgadget@gmail.com> wrote:
>>
>> From: Julia Evans <julia@jvns.ca>
>>
>> This tutorial covers:
>>
>> 1. Creating an empty repo with `git init`
>> 2. Making commits with `git add`, `git commit`, `git diff`, and
>>    `git status`
>> 3. Pushing to code to a Git host on the internet, including creating an
>>    SSH key
>>
>> Signed-off-by: Julia Evans <julia@jvns.ca>
>> ---
>>  Documentation/gittutorial.adoc | 616 +++++++++++++++++++++++++++++++++
>>  1 file changed, 616 insertions(+)
>>  create mode 100644 Documentation/gittutorial.adoc
>>
>> diff --git a/Documentation/gittutorial.adoc b/Documentation/gittutorial.adoc
>> new file mode 100644
>> index 0000000000..617dbae096
>> --- /dev/null
>> +++ b/Documentation/gittutorial.adoc
>> @@ -0,0 +1,616 @@
>> +gittutorial(7)
>> +==============
>> +
>> +NAME
>> +----
>> +gittutorial - Introduction to Git for beginners
>> +
>> +DESCRIPTION
>> +-----------
>> +
>> +This tutorial explains how to import a project's code into Git, make
>> +changes to it, and upload the project to the Internet.
>> +
>> +We'll show you how to use the commands `git commit`, `git add`,
>> +`git diff`, `git status`, and `git push`.
>> +
>> +Command line vs GUI
>> +-------------------
>> +
>> +Git is a command line program, but there are many excellent GUIs for
>> +Git built by the community. For example, if you use an IDE to edit your
>> +code, it might already have a built-in Git integration that you can use.
>> +
>> +In this tutorial, we'll give instructions for the command line version
>> +of Git, but you can also follow along in a GUI. You can also do some
>> +tasks in a GUI and some tasks on the command line. It's up to you.
>
> Since we assume a *nix-ish environment, should we mention that this
> tutorial works best on UNIX-like OSs, or in a Git-for-Windows Bash
> environment, and may need adapting for folks using PowerShell, CMD, or
> some other userspace (not a piece of jargon I would use here,
> probably)? Or does that get covered incidentally by the installation
> instructions?
>
> I'm especially thinking of not confusing a user who sees something
> different or doesn't have an "ls", "cd", etc. (Maybe my Windows
> command line knowledge is shoddy, though, and those parts just kind of
> work close enough for our purposes?)

Yes, great idea, this also inspired me to recruit more Windows testers.
Added a mention of Git Bash.

>> +
>> +What we'll be doing
>> +-------------------
>> +
>> +Git lets you take snapshots of your code, like a checkpoint in a video
>> +game. In this tutorial we're going to explain a very basic Git
>> +workflow, which is:
>> +
>> +1. Create an empty folder
>> +2. Start using Git to manage the code in that folder
>> +3. Create 2 files and tell Git to save a snapshot of them
>> +4. Make changes to one of the files
>> +5. Tell Git to take another snapshot
>> +6. Repeat steps 4-5 any time you want to update your code
>
> I'm very tempted to nitpick "folder" vs "directory," but I'm not sure
> it's worth our time or that of the target audience :) Just note that,
> while "git grep folder" finds way more hits than I was expecting, it
> seems the primary use in our documentation is in reference to IMAP.

Yeah, I thought this might come up :) I don't have very strong feelings
here.

>> +We'll also explain how to use Git to put your code on the Internet.
>> +
>> +Step 1: Make sure Git is installed
>> +----------------------------------
>> +
>> +To do this tutorial, you'll need:
>> +
>> +1. Git to be installed. You might already have it installed,
>> +   and if not there are directions at https://git-scm.com/install/
>> +2. A folder on your computer with code that you want to start managing
>> +   with Git.
>> +
>> +You can check if Git is installed by running this in your terminal:
>> +
>> +------------------------------------------------
>> +$ git --version
>> +------------------------------------------------
>> +
>> +[[step_2]]
>> +Step 2: Introduce yourself to Git
>> +---------------------------------
>> +
>> +The first time you use Git on a computer, it's a good idea to tell Git
>> +your name and public email address. If you don't, you'll get a lot of
>> +warnings from Git. To do this, run:
>> +
>> +------------------------------------------------
>> +$ git config --global user.name "Namey McName"
>> +$ git config --global user.email you@example.com
>> +------------------------------------------------
>> +
>> +The name and email is so that other people you're collaborating with can
>> +know who made the changes. You can set them to anything you want.
>> +
>> +To check if the name and email have been set, you can run these
>> +commands:
>> +
>> +------------------------------------------------
>> +$ git config user.name
>> +$ git config user.email
>> +------------------------------------------------
>
> Ought we recommend the newer forms (git config set, git config get)?
> Or is the idea to remain compatible with older versions, such as the
> 2.32 I happen to have in /usr/bin on unsupported macOS 12.7.6 from
> very old (?) XCode?
>
>> +
>> +Set your default branch name to `main`, by running this command.
>> +Git is going to change its default branch name to `main` soon, so this
>> +sets you up well for the future.
>> +
>> +------------------------------------------------
>> +$ git config --global init.defaultBranch main
>> +------------------------------------------------
>> +
>> +If there's no output, then it succeeded.
>> +
>> +Step 3: Create an empty folder and 2 files
>> +------------------------------------------
>> +
>> +In your terminal, create an empty folder and change directories into it.
>> +Later on you could follow the same steps in this tutorial to take an
>> +existing project and start managing it with Git, but we're going to use
>> +an empty project so that everyone following this tutorial has the exact
>> +same files.
>> +
>> +For example, run these commands to make a folder called `myproject`
>> +
>> +------------------------------------------------
>> +$ mkdir myproject
>> +$ cd myproject
>> +------------------------------------------------
>
> I don't know, and I'll probably bias towards what you've already
> written over asking for changes, but: does it make things any easier
> to read and follow along with if we "git init myproject" instead?
> Perhaps this version plants the seed that it's not too late to start
> tracking any existing project, though, which is valuable :)
>
> I wonder if you had some rationale for choosing this particular
> sequence? Just curious, now.
>
>> +Create 2 files in this directory, so we have something to work with.
>> +
>> +Make a file called README.md, with these contents:
>> +
>> +------------------------------------------------
>> +We're doing a Git tutorial!
>> +We need 2 lines in this file so here's a second one
>> +------------------------------------------------
>> +
>> +And a file called `hello.py`, with these contents:
>> +
>> +------------------------------------------------
>> +print("hello world")
>> +------------------------------------------------
>> +
>> +Save the two files and keep them open in your text editor so you can
>> +easily edit them later. The exact contents aren't too important, but
>> +we'll use those contents in the example output later.
>> +
>> +You can check that the files are in the right place by running `ls`,
>> +like this:
>> +
>> +
>> +------------------------------------------------
>> +$ ls
>> +------------------------------------------------
>> +
>> +The output should be like this:
>> +
>> +------------------------------------------------
>> +hello.py
>> +README.md
>> +------------------------------------------------
>> +
>> +Step 4: Create a Git repository
>> +-------------------------------
>> +
>> +A Git repository is a folder which stores snapshots. It's usually a
>> +hidden folder called `.git`. Every time you take a snapshot, Git stores
>> +a copy of the contents of every file you're tracking.
>> +
>> +This might feel unbelievable, but Git uses compression so you can easily
>> +store tens of thousands of snapshots without using too much disk space.
>> +
>> +You can create a Git repository for any folder in your computer by
>> +running the command `git init`.
>> +
>> +Run `git init` in the folder you just created, like this:
>> +
>> +------------------------------------------------
>> +$ git init
>> +------------------------------------------------
>> +
>> +Git will reply:
>> +
>> +------------------------------------------------
>> +Initialized empty Git repository in .git/
>> +------------------------------------------------
>> +
>> +You might notice a new hidden folder was created, named `.git`.
>> +
>> +Step 5: Take your first snapshot
>> +--------------------------------
>> +
>> +Next, we're going to take a snapshot of all the files in the directory
>> +and tell Git to store them. Taking a snapshot in Git is a two step
>> +process: first you need to run `git add` and then `git commit`.
>> +
>> +The reason it's a two step process is that sometimes you might not
>> +actually want Git to store a snapshot of _all_ the files in a folder.
>> +For example, if you have a file full of private personal information
>> +called `personal.csv`, and a Python script called `process_data.py`, you
>> +might want Git to keep a snapshot of the Python script but not the
>> +private data.
>> +
>> +For now, we're going to store a snapshot of every file in your folder,
>> +as well as in every subfolder.
>> +
>> +The first step of creating a snapshot is to tell Git which files you
>> +want to include in the next snapshot using `git add`. To tell Git
>> +"include all files", run this command:
>> +
>> +------------------------------------------------
>> +$ git add .
>> +------------------------------------------------
>> +
>> +Next you can create the snapshot using the `git commit` command, like
>> +this. The `-m` flag stands for "message", and it lets you set a reminder
>> +for your future self of what you were doing. The message ("Initial
>> +commit" in this example) can say anything you want.
>> +
>> +------------------------------------------------
>> +$ git commit -m "Initial commit"
>> +------------------------------------------------
>> +
>> +You've now stored the first version of your project in Git! From now on
>> +we're going to use the word "commit" instead of "snapshot", since that's
>> +the term Git uses.
>
> I know we want to limit scope… but I would love to not accidentally
> encourage more use of "-m" for short (often useless?) messages.
> Unfortunately, that drags in the can of worms that is editor
> configuration. At least we can maybe point to
> https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup#_editor
> and 
> https://git-scm.com/book/en/v2/Appendix-C:-Git-Commands-Setup-and-Config#ch_core_editor
> ? idk.

Definitely editor configuration is an issue. I haven't worked out where to
put this yet. I think it's very important to warn users that Git will put you
into `vim` by default, because I think a lot of new Git users will not be
comfortable with vim. Feels like a sticky situation and I still don't quite
know what advice to give people if they aren't comfortable with a
terminal text editor. I think the options are:

- only use `-m` and only write short messages
- use something like `nano`
- use a GUI interface to Git instead, which lets you write commit
messages in a more familiar interface

I don't think we should be prescriptive about commit message length
since the importance of this really depends on the context.

>> +Step 6: Make a change
>> +---------------------
>> +
>> +Now, let's learn how to make a change to a file and review the change you made.
>> +In this example, we'll update the file `README.md`, but you can edit a
>> +different file.
>> +
>> +First open `README.md` in your favourite text editor, make a tiny or
>> +silly change, and save it.
>> +
>> +Next, in the terminal, run the command `git status` to get a summary of
>> +what you changed since the last Git commit.
>> +
>> +------------------------------------------------
>> +$ git status
>> +------------------------------------------------
>> +
>> +The output will look something like this:
>> +
>> +------------------------------------------------
>> +On branch main
>> +
>> +Changes not staged for commit:
>> +  (use "git add <file>..." to update what will be committed)
>> +  (use "git restore <file>..." to discard changes in working directory)
>> +        modified:   README.md
>> +------------------------------------------------
>> +
>> +This output says that we've changed `README.md` since the last time
>> +we committed.
>> +
>> +Next, if you want to see the details of how you've changed `README.md`,
>> +you can run `git diff`.
>> +
>> +------------------------------------------------
>> +$ git diff
>> +------------------------------------------------
>> +
>> +The output will look something like this:
>> +
>> +------------------------------------------------
>> +diff --git a/README.md b/README.md
>> +index 7ebaecb3..5a4ff712 100644
>> +--- a/README.md
>> ++++ b/README.md
>> +@@ -1,2 +1,2 @@
>> + Here are some Python scripts!
>> ++I hope you like them.
>> +------------------------------------------------
>> +
>> +This output says that we added one line, saying "I hope you like them.".
>> +By default Git will show the lines you removed in red, and the lines you
>> +added in green.
>
> I would perhaps prefer to focus on the leading sigils (-, +) than the
> color, if only because colorblindness can lead to all sorts of
> situations with different color setups in the terminal's palette or
> even (probably not our target audience) Git configuration. We could
> probably mention that Git shows added and removed lines in *different*
> colors without being too concerned with which colors those are? (That
> avoids having to twist our words like "your terminal palette's green
> and red" or w/e.)

Thanks, updated to mention the + and -.

>> +
>> +Step 7: Make another commit (easy way)
>> +--------------------------------------
>> +
>> +Now let's tell Git to save the new version of `README.md` by making
>> +another commit! To tell Git to snapshot all files that Git is tracking
>> +and commit them, run this command:
>> +
>> +------------------------------------------------
>> +$ git commit -am "Update README"
>> +------------------------------------------------
>> +
>> +This is similar to the two step process in Step 4 where we used `git
>> +add` and `git commit` to make a commit, but with a shortcut that lets
>> +you do both in just one command. The `-a` stands for "all".
>> +
>> +Step 7b: Make another commit (longer way)
>> +-----------------------------------------
>> +
>> +`git commit -am` is a fast way to snapshot all the files that Git is
>> +tracking. But if you want Git to ignore changes to certain files, you
>> +can instead do a 2-step process like in Step 4 where first you run `git
>> +add` for every file that's been changed and that you want to include in
>> +the next commit, like this:
>> +
>> +------------------------------------------------
>> +$ git add README.md
>> +------------------------------------------------
>> +
>> +and then run `git commit` (without the `-a`), like this:
>> +
>> +------------------------------------------------
>> +$ git commit -m "Update README"
>> +------------------------------------------------
>> +
>> +Step 8: Make a change and throw it away
>> +---------------------------------------
>> +
>> +One of the most useful things about Git is that it lets you safely
>> +experiment: you never need to be scared to change your code because you
>> +can always go back to the old version.
>> +
>> +Before starting to experiment, run `git status` to check the current
>> +state of your Git repository:
>> +
>> +------------------------------------------------
>> +$ git status
>> +On branch main
>> +
>> +nothing to commit, working tree clean
>> +------------------------------------------------
>> +
>> +This "working tree clean" message means that there haven't been any
>> +changes since your last commit.
>> +
>> +Now make a change to your code, and run `git status` again. Like last
>> +time, you should see a message like this:
>> +
>> +------------------------------------------------
>> +$ git status
>> +On branch main
>> +
>> +Changes not staged for commit:
>> +  (use "git add <file>..." to update what will be committed)
>> +  (use "git restore <file>..." to discard changes in working directory)
>> +        modified:   README.md
>> +------------------------------------------------
>> +
>> +This tells us that `README.md` has been changed since the last commit.
>> +But we don't actually want this change, so let's undo it! We can restore
>> +`README.md` back to how it was at the most recent commit using the `git
>> +restore` command.
>> +
>> +**WARNING**: `git restore` can't be reversed! Any time you run it it's
>> +important to be absolutely sure that you're okay with throwing away your
>> +changes since the last commit.
>> +
>> +------------------------------------------------
>> +$ git restore README.md
>> +------------------------------------------------
>> +
>> +Now open `README.md` again. You should see that your changes have been undone.
>> +
>> +You can stop here!
>> +------------------
>> +
>> +The commands we've learned so far (`git init`, `git add`, `git commit`,
>> +`git diff`, `git status`, and `git restore`) are enough to get a lot out
>> +of Git on their own.
>> +
>> +With these commands, you can keep copies of past versions of your code
>> +on your computer and safely experiment with big changes to your code.
>> +
>> +When using Git this way, all of your code just lives on your computer.
>> +But if you want to put your code on the Internet so that other people
>> +can use it or back it up, then you'll need to learn about one more
>> +command: `git push`.
>> +
>> +The rest of this tutorial is about how to upload your code to a Git
>> +repository on the Internet. The high level process is:
>> +
>> +1. Create an account on the Git host
>> +2. Configure Git so that it can login to the Git host to make changes
>> +3. Run `git push origin main` to upload your code
>> +
>> +Navigating the Git host's UI can be tricky, and it's hard for us to
>> +give you exact directions because the UIs change a lot.
>> +
>> +Step 9: Create an account on a Git host
>> +---------------------------------------
>> +
>> +To put your code on the Internet, you need it to be hosted somewhere.
>> +The easiest way to do this is to sign up with a Git host. There's a list
>> +of Git hosts (many of them offer free accounts) at
>> +https://git-scm.com/tools/hosting. GitHub and GitLab are two popular hosts.
>> +
>> +If you're comfortable running a server, there are other ways to host
>> +a Git repository on the internet, like connecting through SSH or open
>> +source Git forge software to your server.
>> +
>> +Step 10: Create an SSH key (if needed)
>> +-------------------------------------
>> +
>> +For Git to upload changes to another Git repository, it needs a way to
>> +login to that repository. One of the most popular ways to do this is
>> +with an SSH key.
>> +
>> +If you don't already have an SSH key, you'll need to create one. On Mac
>> +or Linux, you can check if you already have an SSH key by running:
>> +
>> +-------------------------------------------
>> +$ ls ~/.ssh/*.pub
>> +-------------------------------------------
>> +
>> +If you don't already have an SSH key, run:
>> +
>> +-------------------------------------------
>> +$ ssh-keygen
>> +-------------------------------------------
>> +
>> +`ssh-keygen` will ask you for some details.
>> +The easiest way to do this is to just press Enter at every prompt until
>> +it's done.
>> +
>> +NOTE: All of the advice about how to use SSH in this tutorial is aimed
>> +at getting it to work as quickly as possible. Setting up SSH in a secure
>> +way is very far outside the scope of this tutorial. If you have a
>> +security team in your organization, they might have very different
>> +opinions about the appropriate way to configure authentication with Git.
>> +
>> +Step 11: Tell the Git host your SSH public key
>> +----------------------------------------------
>> +
>> +First, find your SSH key like this (on Mac or Linux):
>> +
>> +-------------------------------------------
>> +$ ls ~/.ssh/*.pub
>> +-------------------------------------------
>> +
>> +That will output something like
>> +
>> +-------------------------------------------
>> +/home/alice/.ssh/id_ed25519.pub
>> +-------------------------------------------
>> +
>> +Copy the contents of that file to your clipboard. It's important that
>> +the filename ends in `.pub` ("pub" stands for "public").
>> +
>> +Then login to your account on the Git host you chose and paste the SSH
>> +key into the appropriate place. Depending on the Git host, it's likely
>> +under "SSH keys" in your settings. If it asks you what type of SSH key,
>> +look for something like "Authentication Key".
>> +
>> +Once you've done this, you're done! Git will automatically use your SSH
>> +key to try to connect.
>> +
>> +Step 12: Create an empty Git repository on the Git host
>> +-------------------------------------------------------
>> +
>> +Go to the Git host's website and create a new Git repository.
>> +
>> +**WARNING**: If you create a public repository and push your repository
>> +to it, then your name and email address, as well as the contents of
>> +any files you committed and every previous version of those files, will
>> +be on the public internet. Some Git hosts have the option to create
>> +a private repository instead, to keep your information private.
>> +
>> +Step 13: Find the address of the repository
>> +-------------------------------------------
>> +
>> +Now, find the address of the repository on your Git host. It should look
>> +something like this:
>> +
>> +-------------------------------------------
>> +git@git.example.com:username/repo.git
>> +-------------------------------------------
>> +
>> +(where `example.com`, `username` and `repo` will be replaced with the
>> +actual values).
>> +
>> +If you can only find an address starting with `https://`, then
>> +you can often translate it to the SSH format by replacing `https://`
>> +with `git@` and replacing the `/` after the domain name with an `:`.
>> +Here's how:
>> +
>> +-------------------------------------------
>> +https://git.example.com/username/repo
>> +^^^^^^^^               ^
>> +replace with "git@"    replace with ":"
>> +-------------------------------------------
>
> This is, of course, forge- and remote- dependent :) but I think it's
> *probably* ok for the tutorial.
>
> When you mentioned HTTPS-to-SSH translation, I was thinking of the
> config-based URL rewrite mechanism, aha! I definitely don't think we
> should go there ;)

Yeah, I thought about the config-based rewrites too and I don't think
we should mention it either :)

>> +
>> +Step 14: push your changes
>> +--------------------------
>> +
>> +Finally, we're ready to send the information in your local Git repository
>> +to the one on the internet!
>> +
>> +First, tell Git about the other repository by running `git remote add`
>> +in your terminal
>> +(replace `git@example.com:username/repo.git` with the actual address):
>> +
>> +-------------------------------------------
>> +$ git remote add origin git@example.com:username/repo.git
>> +-------------------------------------------
>> +
>> +This tells Git to save the URL `git@example.com:username/repo.git` in
>> +your Git repository's configuration under the name `origin`, so that you
>> +can use it later. If you make a mistake while doing this, you can run
>> +`git remote remove origin` and try again.
>> +
>> +Then tell Git to send the information, with `git push`
>> +(if this doesn't work, read the "Troubleshooting `git push`" section for advice!):
>> +
>> +-------------------------------------------
>> +$ git push -u origin main
>> +-------------------------------------------
>> +
>> +`origin` refers to the URL we just added (`git@example.com:username/repo.git`),
>> +and `main` is the name of your current Git branch. You can use any name
>> +(not just `origin`), but using `origin` often makes things easier
>> +because it's the default for `git push` and `git pull`.
>> +We haven't covered branches yet, but `main` is the default branch name.
>
> I'm not sure if we should recommend "-u" without being able to explain
> what it does, and… well… you and I have discussed how that's difficult
> :)
>
> Doesn't the tutorial's recipe of always using "git push origin main"
> work just fine? And if we later introduce pull and other
> branch-/remote-stuff that cares about upstreams, we can mention this
> shorthand then?

Yeah, many people asked what `-u` stands for, we added an explanation.
TBD how well that explanation lands though.

>> +
>> +Any time you want to set up a new repository, you can repeat steps
>> +11-13, with one exception: you only need to pass `-u` the first time
>> +you push. Afterwards you can just run the command:
>> +
>> +-------------------------------------------
>> +$ git push origin main
>> +-------------------------------------------
>> +
>> +It should output something like this:
>> +
>> +-------------------------------------------
>> +To example.com:example_username/example
>> + * [new branch]        main -> main
>> +-------------------------------------------
>> +
>> +Troubleshooting `git push`
>> +--------------------------
>> +
>> +There are 3 main errors you might run into when running `git push origin main`.
>> +Getting errors when running `git push` is actually a big part of using
>> +Git, so congratulations! If you get to this part of the tutorial, you
>> +get a little bonus experience in debugging.
>> +
>> +Here's a guide to why they're happening and how to fix them.
>> +
>> +**Problem 1**: You pushed to `main`, but your branch actually isn't called `main`
>> +
>> +Here's the error:
>> +```
>> +$ git push origin main
>> +error: src refspec main does not match any
>> +```
>> +
>> +This might happen if you didn't set `init.defaultBranch` to `main` in
>> +<<step_2,Step 2>>.
>> +
>> +If you want to check the name of your current branch, you can run `git
>> +status`. For example, in this output, the current branch is "master".
>> +
>> +-------------------------------------------
>> +$ git status
>> +On branch master
>> +
>> +...
>> +-------------------------------------------
>> +
>> +To push your branch, you have a few options:
>> +
>> +* rename your branch to `main`, by running `git branch -m main`
>> +  and then run `git push origin main`
>> +* run `git push origin master`
>> +  (where `master` is the name of your actual current branch)
>> +
>> +**Problem 2: SSH error**
>> +
>> +Here's the error:
>> +
>> +-----
>> +$ git push origin main
>> +The authenticity of host 'github.com (140.82.116.3)' can't be established.
>> +ED25519 key fingerprint is: SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
>> +This key is not known by any other names.
>> +Are you sure you want to continue connecting (yes/no/[fingerprint])?
>> +-----
>> +
>> +Git uses SSH to connect during `git push`, and this message happens when
>> +SSH connects to a new site that you haven't connected to before.
>> +
>> +The easiest way to handle this is to type "yes" and press Enter.
>> +
>> +**Problem 3: the repository already exists**
>> +
>> +Here's the error:
>> +
>> +---------------------
>> +$ git push origin main
>> +! [rejected]        main -> main (fetch first)
>> +error: failed to push some refs to 'example.com:example/example.git'
>> +hint: Updates were rejected because the remote contains work that you do not
>> +hint: have locally.
>> +---------------------
>> +
>> +If you see an error like this, it means that when you created the
>> +repository on your Git host, it created a repository with a file in it
>> +to try to help you out. (that's the "work that you do not have locally"
>> +in the error message)
>> +
>> +You can fix this either by deleting the repository and recreating it, or
>> +by running:
>> +
>> +---------------------
>> +$ git push --force origin main
>> +---------------------
>> +
>> +**WARNING**: In general it's quite dangerous to use `--force` because
>> +it can erase work on the online repository in a way that's difficult to
>> +recover. But if you know for sure that you just created the repository 2
>> +minutes ago and there's nothing in it, then it's okay.
>> +
>> +MORE USEFUL GIT COMMANDS
>> +------------------------
>> +
>> +* To tell Git to "un-add" a file that you added by accident, run
>> +  `git rm --cached FILENAME`
>> +
>> +SEE ALSO
>> +--------
>> +linkgit:git-help[1],
>> +
>> +GIT
>> +---
>> +Part of the linkgit:git[1] suite
>> --
>> gitgitgadget
>
> Overall I think this is excellent (and I wish bottom-post replies
> encouraged saying this up front, hm).
>
> Thanks!

Thanks for the review!

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

Ben Knoble wrote on the Git mailing list (how to reply to this email):

> Le 19 oct. 2026 à 10:25, Julia Evans <julia@jvns.ca> a écrit :

Acknowledging the original was a long email to begin with,

>> On Wed, Oct 7, 2026, at 3:48 PM, D. Ben Knoble wrote:
>>> On Tue, Oct 6, 2026 at 3:37 PM Julia Evans via GitGitGadget
>>> <gitgitgadget@gmail.com> wrote:
>>> +[[step_2]]
>>> +Step 2: Introduce yourself to Git
>>> +---------------------------------
>>> +
>>> +The first time you use Git on a computer, it's a good idea to tell Git
>>> +your name and public email address. If you don't, you'll get a lot of
>>> +warnings from Git. To do this, run:
>>> +
>>> +------------------------------------------------
>>> +$ git config --global user.name "Namey McName"
>>> +$ git config --global user.email you@example.com
>>> +------------------------------------------------
>>> +
>>> +The name and email is so that other people you're collaborating with can
>>> +know who made the changes. You can set them to anything you want.
>>> +
>>> +To check if the name and email have been set, you can run these
>>> +commands:
>>> +
>>> +------------------------------------------------
>>> +$ git config user.name
>>> +$ git config user.email
>>> +------------------------------------------------
>> Ought we recommend the newer forms (git config set, git config get)?
>> Or is the idea to remain compatible with older versions, such as the
>> 2.32 I happen to have in /usr/bin on unsupported macOS 12.7.6 from
>> very old (?) XCode?

I think this got missed?

>>> +
>>> +Set your default branch name to `main`, by running this command.
>>> +Git is going to change its default branch name to `main` soon, so this
>>> +sets you up well for the future.
>>> +
>>> +------------------------------------------------
>>> +$ git config --global init.defaultBranch main
>>> +------------------------------------------------
>>> +
>>> +If there's no output, then it succeeded.
>>> +
>>> +Step 3: Create an empty folder and 2 files
>>> +------------------------------------------
>>> +
>>> +In your terminal, create an empty folder and change directories into it.
>>> +Later on you could follow the same steps in this tutorial to take an
>>> +existing project and start managing it with Git, but we're going to use
>>> +an empty project so that everyone following this tutorial has the exact
>>> +same files.
>>> +
>>> +For example, run these commands to make a folder called `myproject`
>>> +
>>> +------------------------------------------------
>>> +$ mkdir myproject
>>> +$ cd myproject
>>> +------------------------------------------------
>> I don't know, and I'll probably bias towards what you've already
>> written over asking for changes, but: does it make things any easier
>> to read and follow along with if we "git init myproject" instead?
>> Perhaps this version plants the seed that it's not too late to start
>> tracking any existing project, though, which is valuable :)
>> I wonder if you had some rationale for choosing this particular
>> sequence? Just curious, now.

And so was this.

Both are fairly minor in the grand scheme of things, so I’ll treat 
silence as « not interesting right now » and not be offended ;)

> Thanks for the review!

You’re quite welcome!

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

"Julia Evans" wrote on the Git mailing list (how to reply to this email):

On Mon, Oct 19, 2026, at 12:49 PM, Ben Knoble wrote:
>> Le 19 oct. 2026 à 10:25, Julia Evans <julia@jvns.ca> a écrit :
>
> Acknowledging the original was a long email to begin with,
>
>>> On Wed, Oct 7, 2026, at 3:48 PM, D. Ben Knoble wrote:
>>>> On Tue, Oct 6, 2026 at 3:37 PM Julia Evans via GitGitGadget
>>>> <gitgitgadget@gmail.com> wrote:
>>>> +[[step_2]]
>>>> +Step 2: Introduce yourself to Git
>>>> +---------------------------------
>>>> +
>>>> +The first time you use Git on a computer, it's a good idea to tell Git
>>>> +your name and public email address. If you don't, you'll get a lot of
>>>> +warnings from Git. To do this, run:
>>>> +
>>>> +------------------------------------------------
>>>> +$ git config --global user.name "Namey McName"
>>>> +$ git config --global user.email you@example.com
>>>> +------------------------------------------------
>>>> +
>>>> +The name and email is so that other people you're collaborating with can
>>>> +know who made the changes. You can set them to anything you want.
>>>> +
>>>> +To check if the name and email have been set, you can run these
>>>> +commands:
>>>> +
>>>> +------------------------------------------------
>>>> +$ git config user.name
>>>> +$ git config user.email
>>>> +------------------------------------------------
>>> Ought we recommend the newer forms (git config set, git config get)?
>>> Or is the idea to remain compatible with older versions, such as the
>>> 2.32 I happen to have in /usr/bin on unsupported macOS 12.7.6 from
>>> very old (?) XCode?
>
> I think this got missed?

It did! Because of the plain text emails it's tough for me to scan the >> and >
to see the replies (">>" and ">" look similar to me) so I missed them, I don't
know if it's possible to set up my email system to make it easier.

I didn't know about `git config set`, I put it on my list to think about. I
claimed at some point in this tutorial that it works on "any version above
2.0", which is a claim I didn't actually check yet, but I do think it's valuable to
support old versions and be explicit about which Git versions you can use the
tutorial with.

>>>> +
>>>> +Set your default branch name to `main`, by running this command.
>>>> +Git is going to change its default branch name to `main` soon, so this
>>>> +sets you up well for the future.
>>>> +
>>>> +------------------------------------------------
>>>> +$ git config --global init.defaultBranch main
>>>> +------------------------------------------------
>>>> +
>>>> +If there's no output, then it succeeded.
>>>> +
>>>> +Step 3: Create an empty folder and 2 files
>>>> +------------------------------------------
>>>> +
>>>> +In your terminal, create an empty folder and change directories into it.
>>>> +Later on you could follow the same steps in this tutorial to take an
>>>> +existing project and start managing it with Git, but we're going to use
>>>> +an empty project so that everyone following this tutorial has the exact
>>>> +same files.
>>>> +
>>>> +For example, run these commands to make a folder called `myproject`
>>>> +
>>>> +------------------------------------------------
>>>> +$ mkdir myproject
>>>> +$ cd myproject
>>>> +------------------------------------------------
>>> I don't know, and I'll probably bias towards what you've already
>>> written over asking for changes, but: does it make things any easier
>>> to read and follow along with if we "git init myproject" instead?
>>> Perhaps this version plants the seed that it's not too late to start
>>> tracking any existing project, though, which is valuable :)
>>> I wonder if you had some rationale for choosing this particular
>>> sequence? Just curious, now.
>
> And so was this.

I didn't see this one either :)

I had no idea `git init myproject` existed! I do think it's nice to
make it more obvious how you could start tracking an existing project.

> Both are fairly minor in the grand scheme of things, so I’ll treat 
> silence as « not interesting right now » and not be offended ;)
>
>> Thanks for the review!
>
> You’re quite welcome!

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

"D. Ben Knoble" wrote on the Git mailing list (how to reply to this email):

On Mon, Oct 19, 2026 at 4:43 PM Julia Evans <julia@jvns.ca> wrote:
>
> On Mon, Oct 19, 2026, at 12:49 PM, Ben Knoble wrote:
> >> Le 19 oct. 2026 à 10:25, Julia Evans <julia@jvns.ca> a écrit :
> >
> > Acknowledging the original was a long email to begin with,
> >
> >>> On Wed, Oct 7, 2026, at 3:48 PM, D. Ben Knoble wrote:
> >>>> On Tue, Oct 6, 2026 at 3:37 PM Julia Evans via GitGitGadget
> >>>> <gitgitgadget@gmail.com> wrote:
> >>>> +[[step_2]]
> >>>> +Step 2: Introduce yourself to Git
> >>>> +---------------------------------
> >>>> +
> >>>> +The first time you use Git on a computer, it's a good idea to tell Git
> >>>> +your name and public email address. If you don't, you'll get a lot of
> >>>> +warnings from Git. To do this, run:
> >>>> +
> >>>> +------------------------------------------------
> >>>> +$ git config --global user.name "Namey McName"
> >>>> +$ git config --global user.email you@example.com
> >>>> +------------------------------------------------
> >>>> +
> >>>> +The name and email is so that other people you're collaborating with can
> >>>> +know who made the changes. You can set them to anything you want.
> >>>> +
> >>>> +To check if the name and email have been set, you can run these
> >>>> +commands:
> >>>> +
> >>>> +------------------------------------------------
> >>>> +$ git config user.name
> >>>> +$ git config user.email
> >>>> +------------------------------------------------
> >>> Ought we recommend the newer forms (git config set, git config get)?
> >>> Or is the idea to remain compatible with older versions, such as the
> >>> 2.32 I happen to have in /usr/bin on unsupported macOS 12.7.6 from
> >>> very old (?) XCode?
> >
> > I think this got missed?
>
> It did! Because of the plain text emails it's tough for me to scan the >> and >
> to see the replies (">>" and ">" look similar to me) so I missed them, I don't
> know if it's possible to set up my email system to make it easier.

No worries! I wonder if your client can color different nesting levels
differently? My iPhone's Mail.app does this and it's really handy.

> I didn't know about `git config set`, I put it on my list to think about. I
> claimed at some point in this tutorial that it works on "any version above
> 2.0", which is a claim I didn't actually check yet, but I do think it's valuable to
> support old versions and be explicit about which Git versions you can use the
> tutorial with.

Sounds good. I prefer to teach folks the "set" version now, but we
both care about some kind of backwards compatibility here, so I'm
happy with whatever you decide.

> >>>> +
> >>>> +Set your default branch name to `main`, by running this command.
> >>>> +Git is going to change its default branch name to `main` soon, so this
> >>>> +sets you up well for the future.
> >>>> +
> >>>> +------------------------------------------------
> >>>> +$ git config --global init.defaultBranch main
> >>>> +------------------------------------------------
> >>>> +
> >>>> +If there's no output, then it succeeded.
> >>>> +
> >>>> +Step 3: Create an empty folder and 2 files
> >>>> +------------------------------------------
> >>>> +
> >>>> +In your terminal, create an empty folder and change directories into it.
> >>>> +Later on you could follow the same steps in this tutorial to take an
> >>>> +existing project and start managing it with Git, but we're going to use
> >>>> +an empty project so that everyone following this tutorial has the exact
> >>>> +same files.
> >>>> +
> >>>> +For example, run these commands to make a folder called `myproject`
> >>>> +
> >>>> +------------------------------------------------
> >>>> +$ mkdir myproject
> >>>> +$ cd myproject
> >>>> +------------------------------------------------
> >>> I don't know, and I'll probably bias towards what you've already
> >>> written over asking for changes, but: does it make things any easier
> >>> to read and follow along with if we "git init myproject" instead?
> >>> Perhaps this version plants the seed that it's not too late to start
> >>> tracking any existing project, though, which is valuable :)
> >>> I wonder if you had some rationale for choosing this particular
> >>> sequence? Just curious, now.
> >
> > And so was this.
>
> I didn't see this one either :)
>
> I had no idea `git init myproject` existed! I do think it's nice to
> make it more obvious how you could start tracking an existing project.

One of today's lucky 10,000, then! :P

I'm more than happy with the mkdir && cd version, even if my fingers
prefer to type less (git init <dir>), so as before I'm happy with
whatever you settle on.

-- 
D. Ben Knoble

@gitgitgadget

gitgitgadget Bot commented Oct 19, 2026

Copy link
Copy Markdown

User "D. Ben Knoble" <ben.knoble@gmail.com> has been added to the cc: list.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:

> So far we've gotten 112 comments from 30ish beta testers who have tried to
> learn Git for the first using this tutorial....

And we waited for 10 hours after seeing this cover letter in
anticipation, but the patches haven't appeared on the list archive.
Does GGG need to be given a gentle nudge somehow?

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Ben Knoble wrote on the Git mailing list (how to reply to this email):

> Le 19 oct. 2026 à 21:24, Junio C Hamano <gitster@pobox.com> a écrit :
> 
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 
>> So far we've gotten 112 comments from 30ish beta testers who have tried to
>> learn Git for the first using this tutorial....
> 
> And we waited for 10 hours after seeing this cover letter in
> anticipation, but the patches haven't appeared on the list archive.
> Does GGG need to be given a gentle nudge somehow?

I received the v2 patches. I rather suspect the list did something interesting (or the archive), or that the messages were too big. 

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Julia Evans wrote on the Git mailing list (how to reply to this email):

> On Oct 19, 2026, at 10:24 PM, Ben Knoble <ben.knoble@gmail.com> wrote:
> 
> 
>> Le 19 oct. 2026 à 21:24, Junio C Hamano <gitster@pobox.com> a écrit :
>> 
>> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>> 
>>> So far we've gotten 112 comments from 30ish beta testers who have tried to
>>> learn Git for the first using this tutorial....
>> 
>> And we waited for 10 hours after seeing this cover letter in
>> anticipation, but the patches haven't appeared on the list archive.
>> Does GGG need to be given a gentle nudge somehow?
> 
> I received the v2 patches. I rather suspect the list did something interesting (or the archive), or that the messages were too big.


I see the patches here in the list archive
https://lore.kernel.org/git/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com/ 

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

"Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:

> From: Julia Evans <julia@jvns.ca>
>
> This tutorial covers:
>
> 1. Creating an empty repo with `git init`
> 2. Making commits with `git add`, `git commit`, `git diff`, and
>    `git status`
> 3. Pushing to code to a Git host on the internet, including creating an
>    SSH key
>
> Signed-off-by: Julia Evans <julia@jvns.ca>
> ---

The goal is well described, and overall the tutorial is well-paced
and avoids common beginner traps.  Since Ben has covered the text
fairly well, the remainder of this message has just some leftover
nitpicks.

> +Step 10: Create an SSH key (if needed)
> +-------------------------------------

Even though AsciiDoc implementations are somewhat lenient to allow
difference by a char or two, but the number of hyphens there must
match the number of chars on the previous line, so add one '-'.

> +For Git to upload changes to another Git repository, it needs a way to
> +login to that repository. One of the most popular ways to do this is
> +with an SSH key.
> +
> +If you don't already have an SSH key, you'll need to create one. On Mac
> +or Linux, you can check if you already have an SSH key by running:
> +
> +-------------------------------------------
> +$ ls ~/.ssh/*.pub
> +-------------------------------------------
> +
> +If you don't already have an SSH key, run:
> +
> +-------------------------------------------
> +$ ssh-keygen
> +-------------------------------------------

It may depend on the system settings, but doesn't this by default
still create id_rsa.pub?  I wonder if we want

$ ssh-keygen -t ed25519

so that it will match what the users will find in the next "Step 11".

> +Step 11: Tell the Git host your SSH public key
> +----------------------------------------------
> +
> +First, find your SSH key like this (on Mac or Linux):
> +
> +-------------------------------------------
> +$ ls ~/.ssh/*.pub
> +-------------------------------------------
> +
> +That will output something like
> +
> +-------------------------------------------
> +/home/alice/.ssh/id_ed25519.pub
> +-------------------------------------------
> +
> +Copy the contents of that file to your clipboard. It's important that
> +the filename ends in `.pub` ("pub" stands for "public").

OK.  I hope users won't paste the ls output above instead by
mistake, but perhaps giving a command like "cat ~/.ssh/id_ed25519.pub"
may make this step harder to make mistakes?

> +Then login to your account on the Git host you chose and paste the SSH
> +key into the appropriate place. Depending on the Git host, it's likely
> +under "SSH keys" in your settings. If it asks you what type of SSH key,
> +look for something like "Authentication Key".
> +
> +Once you've done this, you're done! Git will automatically use your SSH
> +key to try to connect.

> +Step 14: push your changes
> +--------------------------

Upcase "Push your changes" to match other steps.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Julia Evans wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

> On Oct 20, 2026, at 1:11 PM, Junio C Hamano <gitster@pobox.com> wrote:
> 
> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> 
>> From: Julia Evans <julia@jvns.ca>
>> 
>> This tutorial covers:
>> 
>> 1. Creating an empty repo with `git init`
>> 2. Making commits with `git add`, `git commit`, `git diff`, and
>>   `git status`
>> 3. Pushing to code to a Git host on the internet, including creating an
>>   SSH key
>> 
>> Signed-off-by: Julia Evans <julia@jvns.ca>
>> ---
> 
> The goal is well described, and overall the tutorial is well-paced
> and avoids common beginner traps.  Since Ben has covered the text
> fairly well, the remainder of this message has just some leftover
> nitpicks.

Glad to hear it!

>> +Step 10: Create an SSH key (if needed)
>> +-------------------------------------
> 
> Even though AsciiDoc implementations are somewhat lenient to allow
> difference by a char or two, but the number of hyphens there must
> match the number of chars on the previous line, so add one '-'.
> 
>> +For Git to upload changes to another Git repository, it needs a way to
>> +login to that repository. One of the most popular ways to do this is
>> +with an SSH key.
>> +
>> +If you don't already have an SSH key, you'll need to create one. On Mac
>> +or Linux, you can check if you already have an SSH key by running:
>> +
>> +-------------------------------------------
>> +$ ls ~/.ssh/*.pub
>> +-------------------------------------------
>> +
>> +If you don't already have an SSH key, run:
>> +
>> +-------------------------------------------
>> +$ ssh-keygen
>> +-------------------------------------------
> 
> It may depend on the system settings, but doesn't this by default
> still create id_rsa.pub?  I wonder if we want
> 
> $ ssh-keygen -t ed25519
> 
> so that it will match what the users will find in the next "Step 11".

I thought so too, but openssh.org says that the default is ed25519 now:
https://man.openbsd.org/ssh-keygen.1#t

From the release notes it looks like ed25519 has been the default 
since 2023: https://www.openssh.org/txt/release-9.5 .
I’m not sure what the default was before that, though I also thought
the default was still RSA so maybe it was RSA.

I’m inclined to suggest that people just use SSH’s default, since as we move
towards post-quantum cryptography, openssh might change its default key type
again, and if that happens we’d want folks to use the new default instead of
going back to ed25519.


>> +Step 11: Tell the Git host your SSH public key
>> +----------------------------------------------
>> +
>> +First, find your SSH key like this (on Mac or Linux):
>> +
>> +-------------------------------------------
>> +$ ls ~/.ssh/*.pub
>> +-------------------------------------------
>> +
>> +That will output something like
>> +
>> +-------------------------------------------
>> +/home/alice/.ssh/id_ed25519.pub
>> +-------------------------------------------
>> +
>> +Copy the contents of that file to your clipboard. It's important that
>> +the filename ends in `.pub` ("pub" stands for "public").
> 
> OK.  I hope users won't paste the ls output above instead by
> mistake, but perhaps giving a command like "cat ~/.ssh/id_ed25519.pub"
> may make this step harder to make mistakes?

I’ve put it on my list of changes to consider

>> +Then login to your account on the Git host you chose and paste the SSH
>> +key into the appropriate place. Depending on the Git host, it's likely
>> +under "SSH keys" in your settings. If it asks you what type of SSH key,
>> +look for something like "Authentication Key".
>> +
>> +Once you've done this, you're done! Git will automatically use your SSH
>> +key to try to connect.
> 
>> +Step 14: push your changes
>> +--------------------------
> 
> Upcase "Push your changes" to match other steps.

Will do, thanks.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Julia Evans wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

> 
>> +Step 10: Create an SSH key (if needed)
>> +-------------------------------------
> 
> Even though AsciiDoc implementations are somewhat lenient to allow
> difference by a char or two, but the number of hyphens there must
> match the number of chars on the previous line, so add one '-'.

I meant to reply to this one. I wonder if it would be better to
update all the headings to use a different form, like this, because
it’s easy to accidentally get the number of `-` characters wrong when
editing a heading.

== Step 10: Create an SSH key (if needed)

I don’t feel strongly about that though, happy to stay consistent 
with how other pages do it.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Julia Evans <julia@jvns.ca> writes:

> From the release notes it looks like ed25519 has been the default 
> since 2023: https://www.openssh.org/txt/release-9.5 .
> I’m not sure what the default was before that, though I also thought
> the default was still RSA so maybe it was RSA.

Changed in 2023 in upstream likely means many users on mainstream
distros may still be using the old default.

> I’m inclined to suggest that people just use SSH’s default, since as we move
> towards post-quantum cryptography, openssh might change its default key type
> again, and if that happens we’d want folks to use the new default instead of
> going back to ed25519.

I very much agree, but (1) you described that the goal of this
document was to get the users going as quickly as possible, and
giving them the securest possible setting is out of the scope, and
(2) we would need to think what to do with the example in the next
step if we leave it the default here.  The answer to the latter
could be to update it to "something like ... but the filename may
differ depending on the default type of the key".

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Julia Evans <julia@jvns.ca> writes:

>> The goal is well described, and overall the tutorial is well-paced
>> and avoids common beginner traps.  Since Ben has covered the text
>> fairly well, the remainder of this message has just some leftover
>> nitpicks.

My local build of 'seen' just saw these:

gittutorial.adoc:124: section delimiter not preceded by an empty line
gittutorial.adoc:487: section delimiter not preceded by an empty line

I haven't checked what these two lines contain yet.

Thanks.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Julia Evans <julia@jvns.ca> writes:

>> 
>>> +Step 10: Create an SSH key (if needed)
>>> +-------------------------------------
>> 
>> Even though AsciiDoc implementations are somewhat lenient to allow
>> difference by a char or two, but the number of hyphens there must
>> match the number of chars on the previous line, so add one '-'.
>
> I meant to reply to this one. I wonder if it would be better to
> update all the headings to use a different form, like this, because
> it’s easy to accidentally get the number of `-` characters wrong when
> editing a heading.
>
> == Step 10: Create an SSH key (if needed)
>
> I don’t feel strongly about that though, happy to stay consistent 
> with how other pages do it.

As we are getting rid of the old contents altogether and starting a
fresh document whose name happens to be the same one as we have been
using for a long time, consistency within a single document may be
sufficient.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Junio C Hamano <gitster@pobox.com> writes:

> Julia Evans <julia@jvns.ca> writes:
>
>>> The goal is well described, and overall the tutorial is well-paced
>>> and avoids common beginner traps.  Since Ben has covered the text
>>> fairly well, the remainder of this message has just some leftover
>>> nitpicks.
>
> My local build of 'seen' just saw these:
>
> gittutorial.adoc:124: section delimiter not preceded by an empty line
> gittutorial.adoc:487: section delimiter not preceded by an empty line
>
> I haven't checked what these two lines contain yet.

Now I have.  It was the underline-hyphen thing.  The earlier one is
for Step 3. I missed, and the later one is what I pointed out in the
nitpick.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Tuomas Ahola wrote on the Git mailing list (how to reply to this email):

Julia Evans <julia@jvns.ca> wrote:

> 
> 
> > On Oct 19, 2026, at 10:24 PM, Ben Knoble <ben.knoble@gmail.com> wrote:
> > 
> > 
> >> Le 19 oct. 2026 à 21:24, Junio C Hamano <gitster@pobox.com> a écrit :
> >> 
> >> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
> >> 
> >>> So far we've gotten 112 comments from 30ish beta testers who have tried to
> >>> learn Git for the first using this tutorial....
> >> 
> >> And we waited for 10 hours after seeing this cover letter in
> >> anticipation, but the patches haven't appeared on the list archive.
> >> Does GGG need to be given a gentle nudge somehow?
> > 
> > I received the v2 patches. I rather suspect the list did something interesting (or the archive), or that the messages were too big.
> 
> 
> I see the patches here in the list archive
> https://lore.kernel.org/git/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com/ 

Thanks.  That works, and so does

  nntp://nntp.lore.kernel.org/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com .

However, all these fail:

 - nntp://public-inbox.org/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com
 - nntp://gmane.io/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com
 - https://marc.info/?i=6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com
 - https://lwn.net/ml/git/6532e60e30864c9bccfe5be0731c6913aa44d188.1792421748.git.gitgitgadget@gmail.com

Quite puzzling.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

User Tuomas Ahola <taahol@utu.fi> has been added to the cc: list.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Junio C Hamano <gitster@pobox.com> writes:

> Junio C Hamano <gitster@pobox.com> writes:
>
>> Julia Evans <julia@jvns.ca> writes:
>>
>>>> The goal is well described, and overall the tutorial is well-paced
>>>> and avoids common beginner traps.  Since Ben has covered the text
>>>> fairly well, the remainder of this message has just some leftover
>>>> nitpicks.
>>
>> My local build of 'seen' just saw these:
>>
>> gittutorial.adoc:124: section delimiter not preceded by an empty line
>> gittutorial.adoc:487: section delimiter not preceded by an empty line
>>
>> I haven't checked what these two lines contain yet.
>
> Now I have.  It was the underline-hyphen thing.  The earlier one is
> for Step 3. I missed, and the later one is what I pointed out in the
> nitpick.

Regarding the topic in your other message, this discussion helps us
contrast the two styles offered by AsciiDoc.

The Atx-style headers, e.g.,

 = This is a first level header
 == this is a second level header

free us from the need to count characters for Setext-style
headers, e.g.,

 This is a first level header
 ============================
 This is a second level header
 -----------------------------

Besides, counting characters becomes tricky once we step outside
US-ASCII anyway, which is another reason to prefer the modern
Atx-style prefix format.

I find it somewhat harder to notice when a section is at the
wrong level in a document using Atx-style headers.  With
Setext-style, the long underline makes mismatches stand out;
indeed, that is how I caught a handful of mistakes over the
course of this project that I suspect I otherwise wouldn't have
found.  Once found, however, such a mistake is easier to
correct.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email):

Junio C Hamano <gitster@pobox.com> writes:

> "Julia Evans via GitGitGadget" <gitgitgadget@gmail.com> writes:
>
>> So far we've gotten 112 comments from 30ish beta testers who have tried to
>> learn Git for the first using this tutorial....
>
> And we waited for 10 hours after seeing this cover letter in
> anticipation, but the patches haven't appeared on the list archive.
> Does GGG need to be given a gentle nudge somehow?

Now I see them.  Perhaps the list archive, or its nntp interface, or
both were constipated?  I dunno.

@gitgitgadget

gitgitgadget Bot commented Oct 20, 2026

Copy link
Copy Markdown

This patch series was integrated into seen via git@27e3fe4.

@gitgitgadget gitgitgadget Bot added the seen label Oct 20, 2026
@gitgitgadget

gitgitgadget Bot commented Oct 21, 2026

Copy link
Copy Markdown

Junio C Hamano wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

Junio C Hamano <gitster@pobox.com> writes:

> ... indeed, that is how I caught a handful of mistakes over the
> course of this project that I suspect I otherwise wouldn't have
> found.  Once found, however, such a mistake is easier to
> correct.

Sorry, but re-reading my previous message, I realize my preference
was not very clear.  The last sentence there should have ended
with "easier to correct with the ATX-style prefix format."

I do not have a strong preference either way myself.  However, this
is practically a brand-new document.  If you think it would be
easier to adopt and stay consistent with the prefix format, I am
happy to go with that direction.

Thanks.

@gitgitgadget

gitgitgadget Bot commented Oct 21, 2026

Copy link
Copy Markdown

"Julia Evans" wrote on the Git mailing list (how to reply to this email) regarding 41dca2e (outdated):

On Wed, Oct 21, 2026, at 1:16 PM, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
>
>> ... indeed, that is how I caught a handful of mistakes over the
>> course of this project that I suspect I otherwise wouldn't have
>> found.  Once found, however, such a mistake is easier to
>> correct.
>
> Sorry, but re-reading my previous message, I realize my preference
> was not very clear.  The last sentence there should have ended
> with "easier to correct with the ATX-style prefix format."
>
> I do not have a strong preference either way myself.  However, this
> is practically a brand-new document.  If you think it would be
> easier to adopt and stay consistent with the prefix format, I am
> happy to go with that direction.

I do find it easier to stay consistent with the prefix format, but
I also ran into an issue where if I format the DESCRIPTION section
like this:

== DESCRIPTION

then I get this error from `make lint-docs`:

gittutorial.adoc:779: has no required 'DESCRIPTION' section!

So it seems easier for now to stick to the usual format, since
it feels weird to me to mix two different ways of formatting
headings in the same document, and I don't want to update
the linter to understand the other way of formatting headings.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant