Git

In Git, we use version control to create discrete saved states, known as commits, of our project. Each of these commits is part of a broader repository for a project. A remote repository refers to a non-locally stored copy of the repository. This remote contains all the data in the project since the last time anyone pushed the commits they've made to this remote repository. By default, we name this remote repository "origin."

Getting Started

Objects in Git

Blob

A blob is an opaque chunk of binary data, which represents an entire file. Any time a file is updated, a brand new blob is created, with the entire contents of the file. In this way, git is not storage efficient, but it is reliable. If any blob is corrupted, the other blobs will let you generate the file.

... A sidenote I'm adding here in 2020, two years after I wrote the note above: It's called a blob because it's a binary large object 🤦🏻‍♂️ that's pretty clever I gotta be honest

Tree

A tree is a portion of the repository's content at a given point in time.

Tag

A tag is a name for a particular commit that a human can read. By default, a tag is not part of a given commit.

Branches

In git, a pointer is known as a ref. A branch contains a ref to a tip, and includes all commits that can be reached from the tip. The tip is the last commit that was made on a given branch.

The HEAD ref refers to the current branch that the user is working on.

The branch you are working on has a * to identify it.

The Git Index

When you type $ git add . all the files that have been changed are added to the staging area before a commit, otherwise known as the index. The index contains the entire set of files that will be committed, not just those that have been changed. After typing $ git commit the index becomes the next commit.

Typing $ git diff shows the changes that are not staged for commit. It shows you the changes that you have yet to add.

Typing $ git diff --staged shows you the changes that are staged for commit. In other words, it shows you the difference between the index and the most recent commit.

Merging Branches

You can branch off of a current branch, which will create a new branch starting from the head (most recent commit) of a current branch, for example: master.

After you have made your changes, you can merge the changes back into the original branch. To do this, first switch into the original branch, and then type

Commits

Commiting Even Faster

Using the -a and -m flags in conjunction, you can make a commit to a git repository in a single line. This flag will stage and commit all files that have been modified, but will not stage any files that are currently untracked.

git commit -am "My commit"

Using the OS X Keychain

If you clone repos with HTTPS instead of SSH, you're required to specify your username and password every time. That obviously gets old really quickly. If you're on a mac, you can integrate git with the OS X Keychain so that it remembers your username and password for future commands.

git config --global credential.helper osxkeychain

You won't be prompted to specify a username and password. You'll be asked for it the next time you pull using HTTPS from GitHub

If you ever need to reset this information (for instance, after changing your GitHub password), use the erase command

git credential-osxkeychain erase

The next time you clone using HTTPS, you will be prompted for your username and password again.

Imgur

Branches

A note on the figure above, node A is the root commit in this repository. This is a directed graph, where edges are directed toward the parent commit

A branch is a collection of all the commits in a graph that trace back to a tip. The nodes above labeled F, 4, and Z are the tips of each of their respective branches.

Even after you merge two branches (in the case above, E is created from merging D and 2) both branches continue to exist.

The first branch is called the master branch It has this name by default, and it does not have any special properties.

Local Branches

Remote Branches

Configurations

Your configuration file is stored in a few places, and will be searched for in the following order:

System configurations
Configurations that apply to all users of this system
  • File is located at /usr/local/etc/gitconfig.
  • Can be edited with git config --system --edit
Global configurations
Configurations that apply to all projects of this user
  • File location is searched for in-order at the following locations:
    1. $XDG_CONFIG_HOME/git/config
    2. ~/.config/git/config
    3. ~/.gitconfig
Local configurations
Configurations apply to this project only.
  • File is located at $GIT_DIR/config
  • Can be edited with git config --global --edit
  1. $GIT_DIR/config

You can get great suggestions for what should be in a .gitignore file, either locally or globally, by going to gitignore.io

Abandoning Changes

If you committed something you weren't supposed to, and would like to undo your changes, use one of these commands

"HEAD^ means "the commit before HEAD since you just changed HEAD with the commit that was made". Other than HEAD^, you can specify HEAD~2 to reference the 3rd-to-last commit, and so on. You can go actually go back as many commits as you would like, you just type in ~3, ~4 etc.

hub

If you host your repositories on GitHub, you should download their command line tool hub which provides useful functionality for managing your GitHub remote repository directly from your command line.

brew install hub

Then, add eval "$(hub alias -s)" to your .zshrc file.

Creating Signed Commits

Each commit in git is signed by the author of the commit with their cryptographic signature. Usually, this is SSH, but it can be GPG as well.

If you'd like to have GitHub show a Verified tag next to your commits, specify to git on your local machine that you'd like to sign your commits locally

# List all keys as well as their corresponding key ID
gpg -k --keyid-format LONG
# Specify the key ID for git to use for signing commits
git config --global user.signingkey C1C27DC14DB20F99
# Automatically sign commits
git config --global commit.gpgsign true
gpg --full-generate-key

{..notice--warning :""} Note: You'll have to let GitHub know about this new key. To do so, copy the key ID to your clipboard and paste it inside the GitHub profile section for GPG keys.

gpg -k
gpg --armor --export GitHub | pbcopy

Adding Custom Aliases

git config --global alias.stage 'add'
git config --global alias.unstage 'reset'

Direct git commands toward different directory

git -C ~/dotfiles status

Merge conflicts

git config --global --replace-all git.mergetool vimdiff
git config --global --replace-all merge.conflictstyle diff3
git config --global --replace-all mergetool.prompt false

Add this to your ~/.vimrc so that when vimdiff is active, you can simply select window 1, 2, or 3

if &diff
    map <leader>1 :diffget LOCAL<CR>
    map <leader>2 :diffget BASE<CR>
    map <leader>3 :diffget REMOTE<CR>
endif

Add this to your ~/.gitconfig

[merge]
  tool = codemerge
  guitool = codemerge
  conflictstyle = merge
[mergetool "codemerge"]
  cmd = code --wait --diff $MERGED
  trustexitcode = true
  keepbackup = false

Add this to your ~/.gitconfig

[diff]
  tool = codediff
[difftool "codediff"]
  cmd = code --wait --diff $LOCAL $REMOTE

Environment Variables

There are six variables to be aware of when writing a commit, three for the author, and three for the committer. These variables, if found as variables set in your shell, will be used by Git during a commit.

For instance, this is how you would commit files, but at a date and time that was in the past:

GIT_AUTHOR_DATE=TIMESTAMP \
GIT_COMMITTER_DATE=TIMESTAMP \
git commit -m 'Travel back in time'

Where TIMESTAMP is an ISO 8601 timestamp string of a moment in the past, such as the example below:

2021-02-03T12:34:56-08:00

Rename Case-Sensitive Files

If you're developing on a macOS environment, and rename a file directory from File.txt to file.txt, git will not recognize the change. In order to perform a case-sensitive rename of a version-controlled file, you'll need to do it in two steps.

git mv 'Directory' 'temp'
git mv 'temp' 'directory'

Working with files

git ls-files

Output

__main__.py
backtest/backtest.py
functions/metrics.py
symbols/spx.yml
utils/__init__.py
utils/fetcher.py

Git parameters

The main utility you have when exploring the value of parameters set by Git is the rev-parse subcommand

Git Commit Messages

git rebase

git log

Git Large File Storage

Git isn't a utility designed for tracking binary files, such as a compiled C program, or a tarball of an archived directory. For this, one needs to use a helper utility, called git-lfs. This adds lfs as a sub-command to git and stores pointers to the binary files in the repository. git-lfs is, most importantly of all, supported by GitHub.

Git Submodules

the quick brown fox jumps over the lazy dog oh my god

Sometimes you need to use somebody's project as part of your project. It'd be wasteful to copy all of the revisions of their code base into your git repository, as you won't be the one making/reversing those edits.

An excerpt from the book "Pro Git" has come to the rescue:

Git addresses this issue using submodules. Submodules allow you to keep a Git repository as a subdirectory of another Git repository. This lets you clone another repository into your project and keep your commits separate.

Thankfully the git submodule command allows us to use other repositories within our own.

https://docs.github.com/en/packages/guides/about-github-container-registry

The log Subcommand

The clone Subcommand

GitHub Notes

You can now use @me as a filter when performing a search on GitHub. For example, is:issue state:open assignee:@me

GitHub Wikis

You can clone wikis to your local machine, and then make changes to them as you would any other code base.

GitHub Issues

GitHub has a useful shorthand notation for referencing content related to a repository. For instance, you can make references to links and urls using a shorthand syntax, as follows:

USER/REPO#NUMBER

To learn more about the shorthand syntaxes available, see Autolinked references and URLs

GitHub Profile Repository

GitHub supports a secret profile repository feature. If you create a repository at USERNAME/USERNAME, you can add a bio to your profile. GitHub will display the contents of the repo's README.md on your profile page. Try it out:

gh repo create --public USERNAME/USERNAME
cd USERNAME
echo '# Bio' > README.md
git add README.md
git commit -m 'Initialize repository'
git push -u origin master
gh repo view --web

Once you've visited the repository, navigate to your profile to see the change!

GitHub supports the OpenGraph API

TIL GitHub supports Custom Open Graph Images for repositories

GitHub Container Registory

GitHub Security Policy

Security Policy

Reporting a Vulnerability

Create the file SECURITY.md and place it in any of the following locations:

See my example below to learn more about Adding a security policy to your repository

Use this section to tell people how to report a vulnerability.

Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.

---

**Note**: Added this to practice [GitHub's security policy] feature.

-- @austintraver

[GitHub's security policy]: https://docs.github.com/en/code-security/security-advisories/adding-a-security-policy-to-your-repository