dotfiles/notes/shell/git_notes.md
2022-09-07 22:24:18 -06:00

7.8 KiB

Quick start

Git is an indispensable tool for code development, though in reality you'll only use a few commands on a day to day basis. This section provides a quick overview of those commands

    $ git fetch
    $ git status -s
    $ git diff file_1
    $ git add some_dir
    $ git commit -m "Changed some directory"
    $ git switch -c new_branch
    $ git restore file_2
    $ git commit -a
    $ git log --graph --all --oneline --decorate | less
    $ git push

The above represent ~90% of git commands you'll use. For some of these, like the git log command, you should setup aliases

Manual pages

$ man gittutorial
$ man giteveryday

Some useful manual pages for referencing non-specifics

$ man git-rebase
$ git help rebase
$ tldr git rebase

For information on a single command, add a hyphen to separate out the subcommand. If using tldr type the command as you normally would

Referencing commits

While most git commands default to HEAD without a commit passed, they often accept other commits to operate on. Some commands also need another commit to operate, like git merge

$ git show HEAD      # References the current HEAD
$ git show HEAD^     # References one commit above the HEAD
$ git show HEAD^^    # Two commits above HEAD
$ git show HEAD~4    # 4 commits above HEAD
$ git show a22a398   # Commit starting with SHA1 a22a398
$ git show v0.2.0    # Commit tagged with v0.2.0
$ git show master    # Tip of the master branch
$ git show origin/dev  # Tip of the local copy of the origin's dev branch

Various examples of referencing commits. These can be mixed together for more complicated referencing, though that's not too common

$ git show HEAD~4..     # All commits from 4 commits before to HEAD
$ git show v2.0..HEAD^  # Commits from tag v2.0 to one before HEAD

Some commands accept ranges of references. As expected, if one end of the range is missing, it'll use a default upper/lower bound

$ git merge origin/master^

Merges one before the tip of the local copy of the origin's, possibly outdated, master branch to the current branch. Very useful when working offline

Project setup

New projects

$ git init

Create a new git repository in the current directory with a master branch

$ git remote add origin git@github.com:Aizuko/configs.git
$ git remote add origin ssh://git@github.com:22/Aizuko/configs.git

Sets up a remote origin on GitHub. This example uses ssh to connect, though often http will also be supported. The second example specifies port 22

$ git push --set-upstream origin master

Pushes the master branch to the remote origin

Using a previous project

$ git clone ssh://git@github.com/Aizuko/configs.git
$ git clone https://github.com/Aizuko/configs.git

Clone a git repository from a remote. Everything will automatically be setup

$ git clone -b dev --single-branch --depth=1 ssh://git@github.com:22/Aizuko/configs.git

Clone the tip of the dev branch. Useful for saving storage, if you only need the latest commit

.git/config
[remote "origin"]
 - fetch = +refs/heads/dev:refs/remotes/origin/dev
 + fetch = +refs/heads/*:refs/remotes/origin/*

Sets git to synchronize all branches from origin, instead of just dev

$ git remote -v

List the remotes for this repository. Often useful if you want to change the connection protocol

$ git remote set-url origin git@github.com:Aizuko/configs.git

Changes a remote. You'll rarely use this outside of changing protocols

$ git clone --depth=1 git://github.com/Aizuko/configs.git

Quick way to clone a Github repository without needing to login

$ git remote add upstream git@github.com:22/Aizuko/configs.git

Sets up another remote to track. Particularly important with forked branches

Branches

Branches are a way to organize workflow into separate goals. This allows commits for a feature that is still in development. Git recommends making a lot of cheap branches and deleting them once merged

$ git branch -a

Lists all the branches on the local system

Git checkout changes

git checkout was one of the most common commands to run in git, since it handled way too much. Starting in git 2.23 the command has been split into two new commands. switch deals with branches while restore resets files

$ git restore file.txt
$ git checkout file.txt

Restore a file to how it was in the HEAD's commit

$ git restore --source HEAD^ file.txt
$ git checkout HEAD^ file.txt

Restore the file to match the commit one before the HEAD

$ git switch master
$ git checkout master

Switch to the master branch

$ git switch -c dev
$ git checkout -b dev

Create a new branch called dev

Removing branches

Once a branch's goal has been achieved and merged, there's no use in keeping it around. Having a bunch of old branches is simply confusing

$ git branch --merged

Shows which branches have been merged. Many of these are often safe to delete

$ git branch -d merged_branch

Deletes a branch locally. Only deletes branches that have been fully merged into an upstream, so often the remote. There's no fear in losing commits this way

$ git branch -D deadend_branch
$ git branch -f -d deadend_branch

Force deletes a local branch, regardless of whether it's been merged. You can, and likely will, lose commits this way. This should only be used for local experimental branches that quickly hit a dead end in development

$ git push origin --delete merged_branch

Deletes the branch on the remote repository as well

Tagging

Tags can be added to make referencing certain commits easier. Tags can often be used instead of the rather complicated SHA1 to reference commits

$ git tag -a v0.1.0 a22a398
$ git tag -a v0.1.0 a22a398 -m "First version"

Creates an annotated tag for the commit a22a398. The tag will be automatically signed

$ git tag -a -f v0.2.0 a22a398 -m "Add compact statusline"

Overwrite previous tag for a commit with a new tag. This isn't a problem for tags that are only local to the system. Do not attempt for remote tags

$ git push origin v0.1.0
$ git push origin --tags v0.1.0 v0.2.0

Push up locally created tags to the remote. Tags need to be explicitly pushed. Note that undoing tag pushes is really hard and shouldn't be done

Ignoring files

In general there are 2 types of files you won't want to track with git: build artifacts and files specific to your computer. Stopping git from tracking these is done through git ignore pattern files

./.gitignore

Sits in the root of a git repository as a local ignore file. This will be committed to the repository, so other users will ignore the same files

./.git/info/exclude

Acts like a .gitignore file specific to your system's repository. It will not be committed. Useful for random files you have lying around

~/.gitignore_global

A gitignore that applies to every repository for the user. It will not be committed to any particular repository, so it's more similar to a git exclude file. It doesn't need any particular name, just source it in ~/.gitconfig:

[core]
	excludesfile = ~/.gitignore_global

.gitignore files use pattern matching similar to regex

target
target/**/*

Ignores anything in and including the ./target directory

target/notes_[0-9].md
target/notes_?.md

Doesn't track any note files from 0-9, though will track anything higher, such as target/notes_12.md. A ? matches any one character, in this case also matching target/notes_a.md

!target/*_notes_*/lec_*.md

Track any lecture file in any notes directory in target. This can match paths like target/cmput_notes_1/lec_2.md and target/japan_notes_12/lec_passive.md

$ git rm --cached file.txt

In shell, removes a currently tracked file from tracking. This won't remove the file from your system. Useful when you start ignoring a previously tracked file

[//]: # ex: set ft=markdown:tw=80: