Brief Git Notes

John Gabriele

2021-06-30

There are lots of great docs on git elsewhere (for a few, see the links below), so I’m only including a few basic reminders to myself herein. You can always read the git man pages via one of the following (e.g., the docs for git branch):

git help branch
git branch --help
man git-branch

or read them online at https://git-scm.com/docs.

See also:

man gittutorial
man giteveryday
man gitglossary

Note that running “git foo” executes the git-foo program.

Overview

Your repository is the .git directory at the top-level of your project.

A commit is a patch. However, the term also refers to the current state of your branch — that is, the sum of all the commits that lead to this commit (aka, a snapshot). Each commit is identified by a unique name (a SHA-1 hash). A commit has a parent commit (or none if it’s the initial commit, or more than one if it’s a merge).

The git docs draw diagrams of commit histories left to right, like this:

A---B---C

where:

A branch is a named reference to a commit which moves to the next commit when you make a commit to that branch. The term “branch” can also mean the lineage back in history of a given branch.

A remote is a remote repository (as opposed to the local one right in your project directory). When you clone a repository, the one you cloned from is a remote (named “origin”) with respect to your local repository. When you clone a repository, you get all its branches too, though for your local repo their names are prefixed with “origin/”, for example, “origin/this-branch” and “origin/that-branch”.

Note that if you use gitlab (though the same goes for github) and fork someone’s repo using the website UI, you’ll then have your own separate repo on gitlab. If you then clone that (your) gitlab repo to your local machine, “origin” will be your gitlab clone. It’s customary to refer to the originally-cloned-from repo as “upstream”. For your local machine’s repo, both “origin” and “upstream” are remotes. See note below about setting up remotes.

A tag is a named reference to a commit, but it it doesn’t move when you apply more commits (in the way that a branch does).

HEAD is a reference to the current branch. When you checkout a branch, you’re moving HEAD to point to the branch specified, as well as updating the source files in your project to reflect the state of that branch.

The index is a staging area where you add changes for the next commit.

Files in your repository are either tracked or untracked. You can keep a .gitignore file (containing shell glob patterns 1) to indicate files which you don’t want tracked (such as build artifacts). Tracked files may be unmodified, modified, or staged (for the next commit). git status is your friend.

Examples

git --version

# `--global` means what's in your ~/.gitconfig
git config --global user.name "John Gabriele"
git config --global user.email "you@example.com"  # sets it
git config --global user.email                    # gets it

# To see all settings.
git config --global --list

cd my-proj  # Some project files already here, but no git repo yet.
git init
git add .
git commit  # On Debian, drops you into `nano`.
git commit -m "A simple commit message."

# You can also clone a git repo, from, for example, github:
cd ~/dev
git clone https://github.com/some-user/some-proj.git

# Create a new branch based on the current branch.
git branch   {new-branch}
git checkout {new-branch}   # switches to new-branch
git add .   # add all changes to index (changes will be staged)
git add -p  # interactive add
git status

# Tag the most recent commit. So you can call the commit
# "v1.0" instead of by it's hash.
git tag -a v1.0 -m "Ok, this is pretty stable now."

git log            # show the full log, most-recent at the top
git log --oneline  # condensed output
git log foo.txt    # show only this file's history
git log --stat     # include some abbreviated stats
git log -3         # show only the last three commits
git log -p         # includes diff content (the patches)
git log --pretty=oneline  # one line per commit
git log --since=1.week    # only since 1 week ago (--after)
git log --until=1.week    # up until   1 week ago (--before)
# other options:
# --author
# --committer
# --grep       search string in commit message
# -S           search string in modified code

# Undo whatever changes commit {sha1-sum} made. The reversion itself
# shows up as a new commit.
git revert {sha1-sum}

git rm  # rm's the file(s) and then stages the changes.
git mv  # or you could do `mv` then `git add`.

git diff           # diff betw what's staged --> working dir
git diff --staged  # diff betw prev commit   --> what's staged
git diff --cached  # same

git fetch origin master  # Get the most recent commits from origin.
git merge                # Merges into your current branch.

git push {remote} {branch}
# Ex, to push the changes on your master branch to the origin repo:
git push origin master
git push  # Push the current branch to the remote branch of the same name.

If you get a merge conflict, you need to manually edit the file, do a git add, then commit. git merge --abort to cancel a merge.

If you want to make changes to someone else’s repo, first fork it (hit the web UI fork button), then clone your fork to your local machine. Then:

cd the-proj
git remote -v  # see all your remotes, verbosely
git remote add upstream https://github.com/{original-owner}/{repo-name}.git
git remote -v  # should now see upstream in there as well
# Later, when you need to sync up:
git fetch upstream
# If everything's done on master:
git checkout master
git merge upstream/master

If you’ve created a new repo on your local machine, and want to also have it on github, click the create a new repo button on github, then from your project’s directory:

git remote add origin https://github.com/{your-github-username}/{your-proj-name}.git
git push -u origin master

Todo:

git reset
git reset --hard

Your .gitconfig

Straight from what Eeevee suggests, in addition to your name and email, add:

[merge]
    conflictstyle = diff3

so that conflicts look like:

<<<<<<< HEAD
what you changed it to
|||||||
what it was originally
=======
what they changed it to
>>>>>>> master

(that is, the diffs also include “what it was originally”).

Links


  1. See https://github.com/github/gitignore for a helpful collection of .gitignore template files.↩︎