These instructions are for the command line git interface, used in the terminal on Linux or MacOS, or in Git Bash on Windows.

How to use Git for stuff

Version control is great. Saving different states that a project's been in is great. Separating work on different things into different branches is probably great, I don't do it much.

When first setting up git on a computer it's necessary to set an email address and a name. These are saved as part of every commit and are used for tracking who does what. This is done with two commands:

It's possible to omit the --global flag to set an email and name for the current repository only. I don't know if the email needs to be the same as the one for your GitHub / other hosting account, but mine is. And I just set my name to be my email as well.

My usual workflow is that I create a new git repository for every new thing that I work on. Godot projects. Websites (hello!). A programming language or exercise that I've decided to try out.

I initialise the new repo after I've done some stuff, I create the new repo on my GitHub account, and I connect the two and upload. Creating the repo on GitHub can't be done from a terminal, as far as I know. With a series of incantations:

  1. git init (create the new repo in my working directory)
  2. git branch -m main (change the name of the "master" branch to "main")
  3. git add . (add all new files and changes to the upcoming commit)
  4. git commit -m "commit message" (save the commit on my local machine)
  5. git remote add origin git@github.com:k4gi/repo_name (connect this repo to GitHub's repo, giving it the name "origin")
  6. git push -u origin main (push the main branch and its commits to "origin", that is to say, GitHub's repo)

Now the repository is set up for further use, with only some of these steps required later.

If I have an existing repository that I want to download, or if I feel like making the repository before starting work, I can do things a little differently. I can create the repo on GitHub, and then, in the directory I want my working directory to be in:

This way, the local repo is similarly all set up for further use, without having to add an "origin".

The URL form I usually use (git@github.com: ...) is for SSH connections. I can create an SSH key pair on my computer, provide GitHub with the public key, and then clone and push to any of my private repositories without needing my password.

ssh-keygen -t ed25519 creates a new ed25519 key pair for the current user. By default it's saved in ~/.ssh.

If I'm cloning someone else's repository, or if I don't have an SSH key set up, I have to use a HTTP URL form, like https://github.com/k4gi/repo_name.

When I've gone and done some stuff, and want to save it to the cloud, there are a couple steps to take:

  1. git add . (add all new and changed files to the upcoming commit)
  2. git commit -m "commit message" (save the commit locally)
  3. git push (upload the commit to GitHub)

I've written myself a little script called gitpush that I use so I don't have to type this out every time. It also runs git status, which shows me what changes are being made in the commit.

#!/bin/sh

git add .
git status
echo "Enter commit message:"
read msg
git commit -m "$msg"
git push origin

In the event I've done something I don't want to commit, I can cancel the commit with Ctrl+C instead of entering a message.

When I've gone and done some stuff on another computer, it's important to download those changes with git pull. Ideally this is done before I do other, incompatible stuff. If I have done something, though, it's not the end of the world.

In such a case we have entered merge conflict territory. Git will refuse to push any changes if there are incompatible changes you haven't pulled. The repository (or the global config) needs to be set to merge changes. I always set rebase to false with git config pull.rebase false - I don't fully know what effect "rebase true" or "fast-forward only" has. And then, on running git pull, the affected files will be edited to contain both versions of any conflicting lines.

If the setting has not been set, the error message goes as follows:

hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:
hint: You can replace "git config" with "git config --global" to set a default
hint: preference for all repositories. You can also pass --rebase, --no-rebase,
hint: or --ff-only on the command line to override the configured default per
hint: invocation.

The syntax goes like this: a line of <<<< with the name of one source on the end, for example HEAD or a branch name. Then later down the page a separator line of ====. Everything between these two lines belongs to the aforementioned source. Further down the page is a line of >>>> with the name of the other source, and everything between the separator and this line belong to that source.

The task when resolving a merge conflict is to sort out which lines should stay and which should go, then to delete all the <, = and > lines, then to commit and push the changes. It's not as scary as it looks :)

Sometimes I want to make changes to other peoples' projects or work collaboratively. But not often!, so I can never remember how branching or upstream works!

I create a branch in a project when I'm working with other people or when I want to do some experiment. By default a git repository will be on the main or master branch. One way to check is to run git status, which if you haven't made any local changes will say something like this:

On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

It's important to note that Your branch is up to date with 'origin/master'. is not necessarily true - git makes this assertion without checking, and I have to remember to run git pull to check myself.

For a list of what branches there are, run git branch. To switch to an existing branch, use git checkout branch_name.

To create a new branch use git checkout -b new_branch_name. The new branch will be based on the branch that is currently "checked out".

It's also possible to "check out" a specific commit. Running git log will show a list of all commits in the past that led up to the current state of the branch, in reverse chronological order, most recent first. Each commit can be identified by a long string of letters and numbers that I suppose is a hash of some sort. I can run git checkout 2d79... to change my local copy of the repository to an earlier version.

When I do so, git gives me a warning:

Note: switching to '2d79...'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by switching back to a branch.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -c with the switch command. Example:

  git switch -c <new-branch-name>

Or undo this operation with:

  git switch -

Turn off this advice by setting config variable advice.detachedHead to false

HEAD is now at 2d79... Making sure all assets are commited

What's this? Git is talking about using a switch command. That's different to the checkout I've been talking about!

Fear not, after a brief squiz at StackOverflow it seems that git switch is just an alternate way of doing the same thing, that is designed to be less ambiguous in some circumstance or other. git switch -c new_branch is equivalent to git checkout -b new_branch, and git switch - is equivalent to git checkout -. Git does love its magical keywords.

Notably, after "checking out" an earlier commit, any commits in the future from there won't be shown in git log.

An important part of making branches is to later merge those branches back from whence they came . . . (to be continued)

It has come to my attention that when a new branch is created on the remote copy of a repository, that branch is not automatically downloaded to the local copy when using git pull. I'll run through one way to download the new branch.

  1. git branch -a to see all branches, local and remote:
* master
  remotes/origin/new_remote_branch
  remotes/origin/master
  1. git checkout new_remote_branch to download and switch to the new branch:
Switched to new branch 'new_remote_branch'
Branch 'new_remote_branch' set up to track remote branch 'new_remote_branch' from 'origin'.