Version Control#


Table of Contents#


Git#

Getting Started#

Want to get good at using Git and GitHub? Read the following books; work through the following resources; and practice on in your development environment along the way!

git help tutorial
git help tutorial-2
git help everyday

[ d ] Everday Git

[ d ] GitHub’s Git Guides

[ book ] Chacon, Scott & Ben Straub. (2014). Pro Git: Everything You Need to Know About Git, 2nd Ed. Apress.

[ book ] Ponuthorai, Prem Kumar & Jon Loeliger. (2022). Version Control with Git: Powerful Tools and Techniques for Collaborative Software Development. 3rd Ed. O’Reilly.

Installation#

Git for Windows

Git is installed at the following default location.

C:\Program Files\Git

“Add ‘open with code action’ to Windows Explorer File Context menu” adds an option to the right-button-menu in the file explorer to open a file directly with Visual Studio Code (with this option you can open Visual Studio Code directly from a file.).

Configuring git#

Determine your version of git.

git version

or

git -v

or

git --version

Set your name and email.

git config --global user.name "<name>"
git config --global user.email "<email>"

View your configuration settings.

git config -l

or

git config --list

Use the following variant for more information about your configuration.

git config -l --show-scope --show-origin

The location of your config files depends on your system.

./.git/config  (local)
~/.gitconfig   (global)
/etc/gitconfig (system)
./.git/config  (local)
~/.gitconfig   (global)
/etc/gitconfig (system)
./.git/config                      (local)
C:\users\<user>\.gitconfig         (global)
C:\Program Files\Git\etc\gitconfig (system)

Configuring git some more#

The following instruction set is based on these documents.

Set vim as git’s default text editor.

git config --global core.editor "vim"

Set VS Code as git’s default text editor.

git config --global core.editor "code --wait"

Configure Git to ensure line endings in files you checkout are correct for macOS.

git config --global core.autocrlf input

Configure Git to ensure line endings in files you checkout are correct for Windows. For compatibility, line endings are converted to Unix style when you commit files.

git config --global core.autocrlf true

Creating your first local repo#

1

Navigate to the location in the filesystem where you want to keep your work. This could be the Desktop folder, for example, or some other location you choose.

cd ~/Desktop

Then create a new folder to serve as your local git repo and navigate into it.

mkdir my_local_repo && cd my_local_repo

If you followed these navigation steps exactly then you should now find yourself in a folder called my_local_repo which is located in your Desktop folder. You can verify this by running

pwd

and you should see the following output.

/Users/<user>/Desktop/my_local

2

Your new folder is not yet a git repo. You can verify this by trying to run a git operation.

Run

git status

and you should receive the following error message.

fatal: not a git repository (or any of the parent directories): .git

You can verify this further by inspecting the current folder: running command ls produces no output since it is empty. (Command ls “lists” the contents of the folder.)

Run the command git init to transform this folder into a git repo. This command initializes a new git repository in the current folder and option -b for “branch” names the default branch.

Run

git init -b main

and you should see the following message.

Initialized empty Git repository in /Users/<user>/Desktop/my_local_repo/.git/

Now, git operations should work as intended and you’ll notice that the current folder is no longer empty.

Run

ls -A

and you should see the following output.

.git

3

Taking a peek inside folder .git reveals a lot of stuff which you don’t need to worry about yet.

tree .git

You should see the following output.

.git
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   ├── push-to-checkout.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 17 files
  • logs

  • COMMIT_EDITMSG

  • index

  • packed-refs

Setting up an SSH key for authentication#

This instruction set is based on the following documents:

1

Generate a new public-private key pair. Make sure to replace email@example.com with your own comment.

ssh-keygen -t ed25519 \
-f ~/.ssh/id_ed25519_github_personal \
-C "<email@example.com>"
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_github_personal -C "email@example.com"

2

You will be prompted to type a passphrase for your SSH key. Give your SSH key a strong passphrase and make sure to store it somewhere safe (e.g., with a password manager).

Type your passphrase once and then press Enter.

Type your passphrase again and then press Enter again.

3

Start the SSH agent in the background.

eval "$(ssh-agent -s)"

4

Add the SSH key to the SSH agent.

ssh-add --apple-use-keychain ~/.ssh/id_ed25519_github_personal
ssh-add ~/.ssh/id_ed25519_github_personal

5

Setup the SSH config file.

Compatible shells:

  • Bash

  • Git Bash

  • Zsh

  • other Unix

echo '
Host github.com
  AddKeysToAgent yes
  Hostname       github.com
  IdentityFile   ~/.ssh/id_ed25519_github_personal
  Port           22
  UseKeychain    yes
  User           git
' >> ~/.ssh/config

Compatible shells:

  • Bash

  • Git Bash

  • Zsh

  • other Unix

echo '
Host github.com
  AddKeysToAgent yes
  Hostname       github.com
  IdentityFile   ~/.ssh/id_ed25519_github_personal
  Port           22
  User           git
' >> ~/.ssh/config

echo for zsh echo -e for bash

echo -e '\nHost github.com\n  AddKeysToAgent yes\n  Hostname github.com\n  IdentityFile ~/.ssh/id_ed25519_github_personal\n  Port 22\n  UseKeychain yes\n  User git' >> ~/.ssh/config

echo for zsh echo -e for bash

echo -e '\nHost github.com\n  AddKeysToAgent yes\n  Hostname github.com\n  IdentityFile ~/.ssh/id_ed25519_github_personal\n  Port 22\n  User git' >> ~/.ssh/config

Then run

cat ~/.ssh/config

and verify that the contents of file ~/.ssh/config contain the following text.

Host github.com
  AddKeysToAgent yes
  Hostname       github.com
  IdentityFile   ~/.ssh/id_ed25519_github_personal
  Port           22
  UseKeychain    yes
  User           git
Host github.com
  AddKeysToAgent yes
  Hostname       github.com
  IdentityFile   ~/.ssh/id_ed25519_github_personal
  Port           22
  User           git

6

Copy the public key to the clipboard.

tr -d '\n' < ~/.ssh/id_ed25519_github_personal.pub | pbcopy
cat ~/.ssh/id_ed25519_github_personal.pub | clip

7

In the web browser, navigate to your GitHub account.

Select “Settings” > “SSH and GPG Keys” and then click the green button “New SSH key” and paste your public key in the field “Key”.

Give your key a “Title” which refers to the particular machine holding the associated private key (e.g., Dave’s MacBook Pro).

If you would like to sign your commits, you may repeat this process a second time with the same “Key” and “Title” but witg the “Key type” set to Signing Key rather than Authentication Key. Make sure to check the box under “Vigilant Mode” and see the end of this section to finish setting up your signing key.

Open your web browser > navigate to gitlab > your account > Preferences > SSH keys > New SSH key

Give your key a “Title” which refers to the particular machine holding the associated private key (e.g., Dave’s MacBook Pro).

8

Once the public key has been added to your GitHub account, test the remote connectio from the terminal.

ssh -T git@github.com
ssh -T git@gitlab.com

If the remote connection is established, you may see a confirmation message similar to the following.

> Hi username! You've successfully authenticated, but GitHub does not
> provide shell access.
Welcome to GitLab, username!

Setting up an SSH key for signing#

This instruction set is based on the following documents:

In the terminal, run

git config --global gpg.format ssh &&
git config --global user.signingkey ~/.ssh/id_ed25519_github_personal.pub &&
echo "$(git config --get user.email) namespaces=\"git\" $(cat ~/.ssh/id_ed25519_github_personal.pub)" >> ~/.ssh/allowed_signers &&
git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers &&
git config --global commit.gpgsign true &&
cat ~/.gitconfig

Verify that the contents of file ~/.gitconfig contain the following text.

[commit]
  gpgsign = true
[gpg]
  format = ssh
[gpg "ssh"]
  allowedSignersFile = ~/.ssh/allowed_signers
[user]
  signingkey = ~/.ssh/id_ed25519_github_personal.pub

Managing remotes#

Add a remote named origin with the URL git@github.com:USER/REPO.git where USER and REPO are your own GitHub username and GitHub repo name, respectively.

git remote add origin git@github.com:USER/REPO.git

Change the remote origin’s SSH URL to git@github.com:USER/REPO.git, where USER and REPO are your own GitHub username and GitHub repo name, respectively.

git remote set-url origin git@github.com:USER/REPO.git

Remove references to remote origin from local.

git remote rm origin

Get the remote’s URL.

git remote -v

Connect a local to a pre-existing remote#

1

cd .../local

2

git init

3

echo "# My New Repo" >> README.md

4

git add README.md

5

git commit -m "<message>"

6

git branch -M main

7

git remote add origin git@github.com:<github-username>/<github-repo-name>.git

8

git push -u origin main

Pushing changes from a local to a remote#

1

git status -bs

2

git add file1 file2

3

git status -bs

4

git commit -m "my commit message"

5

git status -bs

6

git push [-u origin <branch>]

7

git status -bs

The working directory and the staging area#

Stage a file (tracked or untracked).

git add <file>

Stage a tracked file for deletion from the repo (and from the working directory).

git rm <file>

Undo changes to a tracked but unstaged file in the working directory.

git restore <file>

Unstage a file while keeping its modifications in the working directory.

git restore -S <file>

Unstage a file and discard its modifications from the working directory.

git restore -SW <file>

Commit all files in the staging area.

git commit -m "<message>"

Commit an unstaged, tracked file.

git commit <file> -m "<message>"

Commit all unstaged, tracked files.

git commit -am "<message>"

Replace the previous commit with the current one.

git commit --amend

Working with GitHub’s CLI#

gh auth login
gh ssh-key list
gh config set git_protocol ssh &&
gh config set editor "code -w" &&
gh config set prompt enabled   &&
gh config set pager cat        &&
gh config list
gh repo list

.gitignore#

You can have a .gitignore file in as many directories in your repo as you would like. A .gitignore file affects its directory and all subdirectories. The pattern matching rules cascade: rules in higher directories can be overriden by inverted rules in subdirectories.

Precedence (from highest to lowest)

  • command line

  • .gitignore file in the same directory

  • .gitignore files in parent directories, proceeding upward

  • .git/info/exclude file

  • the file specified by the configuration variable core.excludesFile

You should place entries into your version-controlled .gitignore files only if the patterns apply to all derived repos universally. If the exclusion pattern is specific to your one repo and is not applicable to anyone else’s clone of your repo then the patterns should go into the .git/info/exclude file since that file is not propagated during clone ops.

Rules

  • blank lines are ignored

  • lines beginning with a pound sign # are comments

  • a literal file name matches a file in any directory with that name

  • a directory name is marked by a trailing slash / and matches the named directory and any subdirectory but does not match a file or a symbolic link

  • a pattern containing shell globbing characters is expanded as a shell glob pattern; the match does not extend across directories

  • an initial exclamation point inverts the sense of the pattern on the rest of the line; any file excluded by an earlier pattern but matching an inversion rule is included; an inverted pattern overrides lower precedence rules

examples

  • * matches zero or more characters

    • Linux: matches everything except slashes

    • Windows: matches everything except slashes and backslashes

  • ** recursively match zero or more directories under the current directory

    • **/*.md recursively matches all markdown files

  • ? matches a single character

  • [ab] either a or b

  • [A-Za-z0-9] matches an alphanumeric character

  • \ escapes a special symbol

  • tmp/

    • tmp/files.log

    • tmp/subdir/files.log

    • parent/tmp/files.log

    • grandparent/parent/tmp/files.log

  • file.log

    • file.log

    • dir/file.log

  • dir/**/file

    • dir/file

    • dir/subdir/file

    • dir/subdir/subsubdir/file

  • **/file

    • dir/file

    • anotherdir/file

    • file

  • file?.log

    • file1.log

    • file2.log

  • !important.log (not ignored)

    • important.log

    • dir/important.log

  • \#*.tmp matches a file name beginning with a pound sign and ending with ‘.tmp’

https://www.toptal.com/developers/gitignore

.gitkeep#

Git keeps track of files, not folders. A folder will only be committed if it contains a file.

Managing branches#

Create a local branch and switch to it.

git switch -c <branch>

Switch to a branch.

git switch <branch>

Delete a local branch.

git branch -d <branch>

Delete a remote branch (and the associated remote-tracking branch).

git push -d origin <branch>

Managing large files#

git lfs version

One-and-done configuration.

git lfs install

Per repo.

git lfs track "*.pad"
git add .gitattributes

Preexisting files?: git lfs migrate (examples)

git lfs migrate info
git lfs ls-files
git lfs clone --depth=1 <url>

Taking a peek inside the .gitattributes file.

Large files with Git: LFS and git-annex

Careful

GitHub warns about files approaching

  • 25 MB via browser

  • 50 MB via command line

Files approaching 100 MB are blocked.

With Git LFS, you can store files up to 2 GB.

Be careful about which assets you deploy via Git LFS and when: monthly storage and bandwidth quotas.

Also, repos should be less than

  • 1 GB (ideally)

  • 5 GB (recommended)

Removing a large file from a repo’s history

Setting up a toy local-remote-collaborator system#

mkdir -p demo/{remote,local,collaborator} &&
cd demo/remote                  &&
git init                        &&
echo "# Demo" > README.md       &&
git add README.md               &&
git commit -m "initial commit"  &&
cd ../local                     &&
git init                        &&
git remote add origin ../remote &&
git pull origin main            &&
cd ../collaborator              &&
git init                        &&
git remote add origin ../remote &&
git pull origin main            &&
cd ..

or

mkdir -p demo/remote            &&
cd demo/remote                  &&
git init                        &&
echo "# Demo" > README.md       &&
git add README.md               &&
git commit -m "initial commit"  &&
cd ..                           &&
git clone remote local          &&
git clone remote collaborator
brew install watch
watch -n1 -d find .

A view of the index and object store#

git init -b main && tree .git
.git
├── HEAD
├── config
├── description
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── fsmonitor-watchman.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── pre-merge-commit.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   ├── pre-receive.sample
│   ├── prepare-commit-msg.sample
│   ├── push-to-checkout.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 17 files
  • logs

  • COMMIT_EDITMSG

  • index

  • packed-refs

Hosting a web page with GitHub Pages#

To do


Commands#

Command Reference

add#

git add

“make the copy in the index match the copy in the working directory”

  • copy from the working directory to the index if the working directory copy is edited

  • remove from the index if the working directory copy is removed

common idioms

  • git add <file> stage a file

  • git add -A or git add . stage all files

  • git add -n dry-run

  • git add -v verbose

  • git add -p or git add --patch patch mode

  • git add -f force add (override .gitignore)

git add [ -i | --interactive ]

am#

git am “apply mailbox”

  • git am feature/0001-some-name.patch apply a single patch

  • git am feature/*.patch apply all patches in a directory

annotate#

git annotate

  • git annotate <file> similar to blame, different output format

apply#

git apply

  • git apply path/to/output.diff apply a diff patch file

bisect#

git bisect

  • git bisect start starts bisect session

  • git bisect good <treeish> or git bisect old <treeish> treeish can be branch, sha, tag, HEAD

  • git bisect bad <treeish> or git bisect new <treeish>

  • git bisect reset reset working directory to state prior to bisect session start

blame#

git blame

  • git blame filename.txt annotate file with commit details

  • git blame -w filename.txt annotate file with commit details (ignore whitespace changes)

  • git blame -L 100,150 filename.txt annotate lines 100-150

  • git blame -L 100,+50 filename.txt annotate lines 100-150

  • git blame <sha> filename.txt annotate file at revision

  • git blame <sha> -- filename.txt annotate file at revision

branch#

git branch

  • git branch list local branches

  • git branch -r list remote-tracking branches

  • git branch -a list both local and remote-tracking branches

  • git branch -v list branches (verbose)

  • git branch <branch> create a new branch

  • git branch -M main Rename the current branch to main.

  • git branch --merged [ HEAD | local | origin/remote | 1234567 ] list branches that have been merged into the current branch

    • uses the current branch by default

    • branches whose tips are reachable from the specified commit (HEAD if not specified)

    • the branch tip is in the history of the specified commit

  • git branch --no-merged list branches that have not been merged into the current branch

  • git branch -r --merged list branches that have been merged into the current branch (remote)

  • git branch -r --no-merged list branches that have not been merged into the current branch (remote)

  • git branch -d <branch> Delete a local branch.

  • git branch -D <branch> Delete a local branch regardless of push or merge status

  • git branch --set-upstream-to=origin/main main

  • git branch --move oldname newname rename branch

cat-file#

git cat-file

  • git cat-file -p <hash prefix> - show the contents of an object file

  • git cat-file -t <hash prefix> - show the type of an object file

checkout#

git checkout

  • git checkout discards working directory (unstaged) changes, reverts to most recent commit state

  • git checkout <branch> switch to an existing branch

  • git checkout -b <branch> create a new branch and switch to it

  • git checkout <checksum> detached state

  • git checkout -- <file> remove file from staging area and discard working directory changes too. DEPRECATED! to discard changes to file in the working tree, see git restore <file>

  • git checkout -b <branch> <hash> recover a branch after accidental deletion (use hash of the branch given by reflog)

cherry-pick#

git cherry-pick

  • git cherry-pick [ <sha> | <sha..sha> ]

  • git cherry-pick -e or git cherry-pick --edit edit the commit message (otherwise the previous commit message is used)

  • git cherry-pick --continue

  • git cherry-pick --skip

  • git cherry-pick --abort

clean#

git clean

  • git clean -f remove untracked files from the working directory (doesn’t remove files that are ignored by git or files that are staged or committed)

  • git clean -f -d removes directories too

  • git clean -f -d -n or git clean -f -d --dry-run

clone#

git clone create a complete copy of a repo

  • git clone <url> [<destination>]

commit#

git commit add staged changes to the local repo

common idioms

  • git commit -m '<message>'

  • git commit -m '<message>' <file> combines the two steps git add and git commit for an existing tracked file (does not apply to rm or mv)

  • git commit -am '<message>'

  • git commit -am '<message>' --amend modify the most recent commit (that hasn’t already been pushed)

  • git commit -vv verbose

  • git commit -p patch mode

git commit [ -a | --all ]

  • git recursively traverses the entire repo; stages all known file changes, including removals of tracked files from the working directory; and commits them

more options

git commit [ --dry-run ] [ --interactive ]

low-level equivalent to git commit

git write-tree && echo -n '<message>' | git commit-tree <name>

commit-tree#

git commit-tree

  • git commit-tree <hash prefix>

config#

git config

  • git config -e

  • git config -l --show-scope --show-origin [ --global | --local | --system ]

more

  • git config --global fetch.prune true (CAREFUL! this is a destructive default that may discard remote-tracking branches that you are still using locally)

  • git config --global alias.praise blame

  • git config --global user.name <name>

  • git config --global user.email <email>

  • git config --global init.defaultBranch main

  • git config --global core.autocrlf [input (macOS) | true (Windows)]

  • git config --global core.editor [code --wait | emacs | nano | vim]

  • git config --global pager.branch false

  • git config --global pull.rebase ["false" (default: fast-forward if possible else merge commit) | "true" (rebase when pulling)]

  • git config --global alias.co checkout

  • git config --global alias.br branch

  • git config --global alias.ci commit

  • git config --global alias.st status

  • git config --global commit.gpgsign true

  • git config --global gpg.format ssh

  • git config --global gpg.ssh.allowedSignersFile ~/.ssh/allowed_signers

  • git config --global gpg.ssh.program /Applications/1Password.app/Contents/MacOS/op-ssh-sign

  • git config --global user.signingkey ssh-ed25519 AAAA...

  • git config --global core.editor "'notepad++.exe' -multiInst -notabbar -nosession -noPlugins"

  • git config --global color.ui true

diff#

diff -r repo1 repo2 compare the contents of two repos (e.g., a repo and its clone)

git diff

git diff compare changes in the working directory to those in the index

git diff [ --cached | --staged ] compare changes in the index to those in the previous commit

git diff <from-commit> <to-commit> > output.diff create a diff patch

diff-tree#

git diff-tree compare the differences between two tree objects (shows the changes made to the file structure and contents)

  • git diff-tree <commit1> <commit2>

difftool#

git difftool

  • git difftool --tool-help

fetch#

git fetch changes from the remote repo are copied to the remote-tracking branch

  • git fetch fetches commits and tags from the default remote (origin)

  • git fetch --all fetches commits and tags from all remotes

  • git fetch --tags fetches tags only (with necessary commits only)

  • git fetch -p or git fetch --prune shortcut: prune, then fetch

format-patch#

git format-patch

  • git format-patch -1 <sha> export a single commit

  • git format-patch main or git format-patch main..HEAD export all commits on the current branch that are not in the main branch

  • git format-patch <sha>..<sha> export all commits in the range

  • git format-patch <sha>..<sha> -o ./feature_patches put patch files into a directory

  • git format-patch <sha>..<sha> --stdout > feature_patch output patches as a single file

gc#

git gc “garbage collection”

hash-object#

git hash-object

git hash-object <name>

echo 'hello world' | git hash-object --stdin

help#

git help

  • git help -a list command categories

init#

git init

  • git init setup a local repo

  • git init --bare

log#

git log view the commit history

  • git log or git log HEAD view the commit history reachable from HEAD

  • git log filename.txt lists commits that changed filename.txt (this is a log of this file’s activity in the current branch)

  • git log <branch> show commit history below branch

  • git log --all show commit history below all branches

  • git log --graph

  • git log --oneline or git log --pretty=oneline seven-digit ID + commit message

  • git log --oneline --graph --all [--decorate] useful for visualizing branches

  • git log -p or git log --patch list commits as patches (diffs)

  • git log -2

  • git log -p -2

  • git log --stat

  • git log --pretty=short

  • git log --pretty=full

  • git log --pretty=fuller

  • git log --pretty=format:"%h - %an, %ar : %s"

  • git log --pretty=format:"%h %s" --graph

  • git log -L 100,150:filename.txt list changes to lines 100-150 in filename.txt

  • git log -L 100,+50:filename.txt list changes to lines 100-150 in filename.txt

  • git log --since=2019-05-14

  • git log --author=Dave

  • git log --grep='<regex>' search commit messages

  • git log --grep='nothing' --author=Dave --since=2019-05-04

  • git log --grep='nothing' --grep='commit' --all-match logical and

  • git log --grep='nothing' --grep='commit' --all-match --invert-grep negation

git log operates on a series of commits

ls-files#

git ls-files - show the contents of the index

  • git ls-files [ -s | --stage ] show staged contents’ mode bits, object name, and stage number in the output

  • git ls-files --debug

ls-tree#

git ls-tree

  • git ls-tree --full-tree --name-only -r HEAD List currently-tracked files.

merge#

git merge

  • git merge <branch>

  • git merge --squash

merge-base#

git merge-base

  • git merge-base main new_feature return commit where topic or feature branch diverges from the source branch (shows the commit that is the current base)

mergetool#

git mergetool

mv#

git mv stage a file for renaming in the repo

git mv

is equivalent to

mv foo.html bar.html
git  rm foo.html
git add bar.html

prune#

git prune prune all unreachable objects (part of git’s automatic garbage collection)

pull#

git pull

  • git pull fetch the latest commits from a remote repo and merge them into the current branch; affects only the current branch by default; fetched commits are stored in the associated remote-tracking branch; untracked changes are overwritten (your local repo should be stashed, committed, and free of untracked changes before pulling)

  • git pull -v verbose

  • git pull -r or git pull --rebase rebase instead of merge

  • git pull --rebase=preserve preserve locally-created merge commits (use if commits that you are rebasing include merge commits)

  • git pull --rebase=interactive

  • git pull --allow-unrelated-histories

push#

git push changes in the local repo are pushed to the remote repo

  • git push push current branch

  • git push origin <branch> push branch

  • git push --all push all branches

  • git push -u origin main or git push --set-upstream origin main create a branch in the remote repo called main

  • git push -v verbose

  • git push -f or git push --force force push (CAREFUL! this rewrites the history)

  • git push -d origin <branch> or git push --delete origin <branch> Delete a remote branch (automatically deletes the remote-tracking branch).

  • git push origin <tag> push some tag

  • git push origin --tags push all tags

  • git push origin --follow-tags push annotated tags only

  • git push -d origin <tag> or git push --delete origin <tag> Delete a remote tag.

  • git push origin :refs/tags/<tag> delete a remote tag ???

  • git push --force-with-lease allows the push to proceed only if the remote branch’s expected state matches the local branch’s expected state, based on the previously known state of the remote branch; a safer alternative to git push -f as it helps prevent inadvertently overwriting commits that you are not aware of

rebase#

git rebase

  • git rebase main rebase current branch to tip of main

  • git rebase main new_feature rebase new_feature branch to tip of main

  • git rebase --onto newbase upstream branch rewind branch to point of merge with upstream then replay commits in order onto tip of newbase

  • git rebase --continue

  • git rebase --skip

  • git rebase --abort

  • git rebase -i main new_feature interactive mode

  • git rebase -i HEAD~3 rebase the last three commits onto the same branch, with the interactive opportunity to modify them (CAREFUL! destructive; useful for local commits that haven’t been shared with others)

reflog#

git reflog reference logs store updates to branch tips and other references in the local repo

remote#

git remote

  • git remote list remotes

  • git remote -v list remotes (verbose)

  • git remote show <url>

  • git remote add origin <url>

  • git remote get-url origin [--all]

  • git remote rename origin destination

  • git remote rm origin

  • git remote set-url origin <url>

  • git remote prune origin [--dry-run] delete stale remote-tracking branches

reset#

git reset move the current branch pointer to a specific commit/position

  • git reset --soft HEAD~1 undo previous commit and put changes back in the staging area (working directory changes are left alone)

  • git reset --hard HEAD~1 undo previous commit and discard commit changes (working directory changes are discarded and working directory reflects the state of the previous commit) (CAREFULE! destructive)

  • git reset --hard origin/main force an overwrite of your local files by the state of remote main branch

  • git reset HEAD <FILE> [OLD] to unstage; see git restore -S <FILE>

  • git reset HEAD@{1}

  • git reset HEAD^ or git reset HEAD^1 the commit’s first parent

  • git reset HEAD^2 the commit’s second parent

  • git reset HEAD~ or git reset HEAD~1 the commit’s first parent

  • git reset HEAD~2 or git commit HEAD^^ the commit’s first parent’s first parent

  • git reset HEAD~n the commit’s nth parent (n commits before HEAD, the nth generation ancestor of HEAD)

  • git reset -p patch mode

  • git reset <file> move staged file out of staging area (preserve working directory changes)

restore#

git restore

  • git restore <file> or git restore -W <file> or git restore --worktree <file> undo changes to a file in the working directory

  • git restore . or git restore -W . or git restore --worktree . undo changes to all file in the working directory

  • git restore -S <file> or git restore --staged <file> unstage a file

  • git restore -S . or git restore --staged . unstage all files

  • git restore -p patch mode

rev-list#

git rev-list

rev-parse#

git rev-parse

  • git rev-parse <commit> [ --is-bare-repository ] translates a relative commit name to the absolute commit name

revert#

git revert

  • git revert <checksum-id> (does not rewrite the history, but adds a new commit to the history)

rm#

git rm stage a file for removal from the repo

git rm is the inverse of git add: it removes a file from both the repo and the working directory

git rm --cached <file> remove a file from the index only (the copy of the file in the working directory is left alone)

“Using git rm --cached to make a file untracked while leaving a copy in the working directory is dangerous because you may forget that it is no longer being tracked. Using this approach also overrides Git’s check that the working file’s contents are current.”

rm <file> remove a file from the working directory only

git rm <file> remove a file from both the index and the working directory (“Before Git removes a file, it checks to make sure the version of the file in the working directory matches the latest version in the current branch. Use git rm -f to force the removal of the file even if you have altered it since your last commit.”)

git restore --staged <file>

copies the file from commit HEAD into the index so that the index copy and the HEAD copy now match (the copy of the file in the working directory is left alone)

if HEAD lacks the file, this has the effect of removing the file from the index

git reset <file>

copies the file from ommit HEAD into the indext

git restore -SW <file> is equivalent to git checkout HEAD -- <file>

show#

git show

  • git show or git show HEAD show changes of the previous commit

  • git show [ <checksum> | <sha> | <tag> ]

  • git show <checksum> -2

  • git show <checksum> --show-signature

  • git show refs/head/<branch> explicit path to branch; useful if branch name matches tag name for example

  • git show <commit> --stat display a histogram showing inserts, deletion, and modifications per file for a specific commit along with its general commit information

show-branch#

git show-branch

view concise, one-line summaries for the current branch

show-ref#

git show-ref

  • git show-ref --head finds the HEAD of the current branch

stash#

git stash

  • git stash

  • git stash save <name>

  • git stash pop applies the topmost entry in the stash to the working files and removes it from the stash

  • git stash apply applies the topmost entry in the stash to the working files but leaves it in the stash

  • git stash -p patch mode

  • git stash branch <branch> restore some previously stashed work to a new branch

  • git stash show -p stash@{2} see the details of the changes in the first of three stash entries

status#

git status - query the state of the index (compares the virtual tree state with the working tree and displays the difference as the output)

  • git status

  • git status -bs

  • git status -u

  • git status -v

  • git status -vv

submodule#

git submodule

switch#

git switch

  • git switch <branch> switch to branch

  • git switch -c <branch> create a new branch and switch to it

  • git switch - return to the previously checked out branch

symbolic-ref#

git symbolic-ref

tag#

git tag

  • git tag or git tag -l or git tag --list list all tags (tags are not tied to branches; they just point to commits regardless of whcih branches they’re on)

  • git tag -l "v2*" list tags beginning with “v2”

  • git tag -n (implies -l) list tags with the first line of each annotation (or commit message if no annotation)

  • git tag -n5 (implies -l) list tags with the first five lines of each annotation (or commit message if no annotation)

  • git tag -s <tag> [<commit>] lightweight tag

  • git tag -s -a <tag> [<commit>] -m 'Version 0.1' annotated tag

  • git tag -d <tag> [<commit>] or git tag --delete <tag> [<commit>] delete a tag

  • git tag -v <tag> [<commit>] verify signed tag

write-tree#

git write-tree create a tree object from the current index

worktree#

git worktree


Resources#

[ h ][ d ][ y ] Git

[ h ][ d ][ y ] GitHub

  • [ h ][ d ][ g ] GitHub CLI

  • [ h ][ d ][ g ] GitHub Pages

[ h ][ d ][ y ] GitLab

[ h ] Graphite

More Git Providers

  • [ h ][ d ] AWS CodeCommit

  • [ h ][ d ] Atlassian Bitbucket

[2020][2019] MIT Missing Semester: Version Control

David Mahler

  • [ y ] David Mahler. (2018). “Introduction to Git - Remotes”.

  • [ y ] David Mahler. (2017). “Introduction to Git - Branching and Merging”.

  • [ y ] David Mahler. (2017). “Introduction to Git - Core Concepts”.

freeCodeCamp

  • [ y ] 11-18-2021. freeCodeCamp. “Advanced Git Tutorial - Interactive Rebase, Cherry-Picking, Reflog, Submodules, and more”. YouTube.

  • [ y ] 09-30-2021. freeCodeCamp. “Git for Professionals Tutorial - Tools & Concepts for Mastering Version Control with Git”. YouTube.

  • [ y ] 07-13-2021. freeCodeCamp. “Git Branch Tutorial”.

  • [ y ] 11-24-2020. freeCodeCamp. “How to Undo Mistakes WIth Git Using the Command Line”. YouTube.

  • [ y ] 05-28-2020. freeCodeCamp. “Git and GitHub for Beginners - Crash Course”. YouTube.

  • [ y ] 09-23-2016. freeCodeCamp. “Git & GitHub”.

YouTube

  • [ y ] GitLab. (14 Nov 2017). “Git Internals - How Git Works - Fear Not The SHA!”. YouTube.

  • [ y ] Mr. P Solver. (16 May 2022). “A Git Tutorial Based On Examples (Code Along!)”. YouTube.

  • [ y ] CS50. (11 Apr 2018). “Git Internals by John Britton of GitHub - CS50 Tech Talk”. YouTube.

  • [ y ] HackersOnBoard. (2013). “[Linux.conf.au 2013] - Git For Ages 4 and Up”.

VS Code

  • [ d ] Using Git source control in VS Code

  • [ e ] Git Graph extension

  • [ e ] Git History extension

  • [ e ] GitLens extension

More

  • [ y ] 02-08-2024. GitButler. “So You Think You Know Git - FOSDEM 2024”.


Texts#

Chacon, Scott & Ben Straub. (2014). Pro Git: Everything You Need to Know About Git, 2nd Ed. Apress. Home.

Ponuthorai, Prem Kumar & Jon Loeliger. (2022). Version Control with Git: Powerful Tools and Techniques for Collaborative Software Development. 3rd Ed. O’Reilly.

Silverman, Richard E. (2013). Git Pocket Guide: A Working Introduction. O’Reilly.

Vinto, Natale & Alex Soto Bueno. (2023). GitOps Cookbook: Kubernetes Automation in Practice. O’Reilly.


Terms#

  • [ w ] Atlassian

  • [ w ] Atomic Commit

  • [ w ] Binary Large Object (BLOB)

  • [ w ] Bitbucket

  • [ w ] Branch

  • [ w ] Centralized Version Control

  • [ w ] Changeset

  • [ w ] Checksum

  • [ w ] Commit (version control)

  • [ w ] Commit (data management)

  • [ w ] Concurrent Versions System (CVS)

  • [ w ] Content-Addressable Storage (CAS)

  • [ w ] Darcs

  • [ w ] Data Differencing

  • [ w ] Delta Encoding

  • [ w ] Detached State

  • [ w ] diff

  • [ w ] diff3

  • [ w ] Directory Structure

  • [ w ] Distributed Version Control

  • [ w ] Edit Conflict

  • [ w ] etckeeper

  • [ w ] Forge

  • [ w ] Git

  • [ w ] Git Provider

  • [ w ] git-annex

  • [ w ] GitHub

  • [ w ] GitLab

  • [ w ] GNU Arch

  • [ w ] GNU Bazaar

  • [ w ] Local Folder

  • [ w ] Local Repository

  • [ w ] Mercurial

  • [ w ] Merge

  • [ w ] Merge Conflict

  • [ w ] Merkle Tree

  • [ w ] Metadata

  • [ w ] Microsoft Visual SourceSafe (VSS)

  • [ w ] Monorepo

  • [ w ] Monotone

  • [ w ] Patch

  • [ w ] patch

  • [ w ] Pull Request

  • [ w ] Remote Repository

  • [ w ] Repository

  • [ w ] Revision Control System (RCS)

  • [ w ] Revision Tag

  • [ w ] Source Code Control System (SCCS)

  • [ w ] Source Code Management (SCM)

  • [ w ] Staging Area

  • [ w ] Subversion (SVN)

  • [ w ] Tag

  • [ w ] Three-Phase Commit Protocol

  • [ w ] Tree

  • [ w ] Tree Structure

  • [ w ] Two-Phase Commit Protocol

  • [ w ] Version Control

  • [ w ] Working Tree


Notes#


\(1\quad\) Working Directory

  • files are edited in the working directory

git add; git rm; git mv

  • “staging a file”; “caching a file”; “putting a file in the index”

  • a file is copied into the object store and indexed by its SHA-1

\(2\quad\) Index (or Cache or Staging Directory) (virtual, mutable data structure)

  • the index collects (or “stages”) alterations to files as a final step before commit (i.e., it tracks what you want to commit)

  • the index caches info about the working directory, and the next revision to be committed

  • the index serves as an interface between the working tree and the object database

  • the index is a binary file and so stores binary data

  • its content is transient; and describes the structure of the entire repo at a specific point in time

    • a virtual tree state representing a tree object that will be referenced by a future commit

    • a sorted list of file pathnames in its virtual state along with its permissions and a reference to the SHA-1 ID of the corresponding blob objects

    • a cached representation of all the blob objects that reflect the current state of the working directory

  • the index does not contain file content

  • plays a role in the following: committing; querying the status of the repo; merging branches

git commit

  • checks the index–not the working directory–to discover what to commit as a single changeset

\(3\quad\) Repo (or Local Commit History) (virtual)

  • the repo is a key-value pair database

Object Store (or Object Database) (append-only data structure) - contains the original data files; log messages; author info; datetimes; etc.

  • Blobs “Binary Large Object” (immutable) - represents a version of a file; contains the file’s data only

    • a version of a file that holds the file’s data; a blob’s name is a hash of its content

  • Trees (immutable) - represents one level of directory info (blob IDs; pathnames; metadata; recursively references other subtree objects); a snapshot of the source tree that contains a list of file names each with a reference to a blob or tree object

  • Commits (immutable) - points to a tree object; links tree objects together into a history; contains the name of the tree object, a timestamp, a log message, and the names of zero or more parent commit objects

    • Author

    • Committer

    • Commit Date

    • Log Message

  • Tags - assigns a human-readable name to an object; a container that contains a reference to another object with metadata

    • Annotated Tag (immutable) - creates an object in the object store

    • Lightweight Tag (mutable) - a reference to a commit object; private to the repo; not stored in the object store

  • Packfile?

Git file classification

  • Tracked - a tracked file is a file that is either in the repo or in the index

  • Ignored - an ignored file must be explicitly declared as such even though it may remain present in the working directory

  • Untracked - an untracked file is a file that is neither tracked or ignored

    • working directory - (tracked + ignored) = untracked

A commit holds a snapshot.

A snapshot is made from the files in the index.


Hashes#

print(10**48 < 2**160 < 10**49)
print(10**48)
print(2**160)
print(10**49)
print(int(1e12) * int(1e12) * 60 * 60 * 24 * 365 * int(1e12))

# a trillion people each of whom produces
# a trillion new unique blobs per second for
# a trillion years
# is still five orders of magnitude less
True
1000000000000000000000000000000000000000000000000
1461501637330902918203684832716283019655932542976
10000000000000000000000000000000000000000000000000
31536000000000000000000000000000000000000000

Commits#

Git stores a commit object that contains

  • a pointer to the snapshot of the content that was staged

  • the author’s name and email

  • the commit message

  • pointer(s) to the parent commit

    • 0 for initial commit

    • 1 for normal commit

    • 2 or more for merge commit

Commits

  • a commit represents a single atomic changeset w.r.t. the previous state: regardless of the number of directories, files, lines, or bytes that change with a commit, either all changes apply or none do.

  • a commit snapshot represents the state of the total set of modified files and directories–which means it represents a given tree state

  • a changeset between two snapshots represents a complete transformation from one tree state to another

Changeset

  • Git also records a mode flag indicating the executability of each file; changes to this flag are also part of the changeset

Absolute Commit Name - references a commit explicitly

  • the globally unique 40-digit hexadecimal SHA-1 commit object ID - globally unique not just for one repo but for any and all repos

Relative Commit Name (ref, symref) - references a commit implicitly

  • a ref points to a SHA-1 within the Git object store (it usually refers to a commit object)

  • a symbolic reference is a name that indirectly points to a Git object

  • each symref has a full name that begins with refs/; there are three namespaces

    • .git/refs/heads/ (local branch names)

      • refs/heads/feature

    • .git/refs/remotes/ (remote tracking branch names)

      • refs/remotes/origin/main

    • .git/refs/tags (tag names)

  • internal

    • .git/HEAD a pointer to the most recent commit in the currently checked-out branch

    • .git/ORIG_HEAD

    • .git/FETCH_HEAD

    • .git/MERGE_HEAD

    • .git/CHERRY_PICK_HEAD

  • ref^n is the n-th parent of commit ref

  • ref^ is the same as ref^1

  • ref^^ is the same as ref~2 and is the first parent of the first parent of commit ref

  • ref~n is the first [ parent, grandparent, great-grandparent, etc. ] of commit ref

  • ref~ is the same as ref~1

  • ^ref exclude commit ref

set difference

  • X..Y the set of commits starting after X up to and including Y; or ^X Y all commits reachable from Y minus all commits up to and including X

  • ..Y is equivalent to HEAD..Y

  • X.. is equivalent to X..HEAD

set symmetric difference (the set of commits that are reachable from either or but not both)

  • X...Y = X Y --not $(git merge-base --all X Y)

  • “show everything in branch X or in branch Y but only back to the point where the two branches diverged”

Example

b..e = ^b e

= e - b = {a, b, c, d, e} - {a, b}

= c d e

                      main
                     /
a <- b <- c <- d <- e
          -    -    -

Example - main at v is merged into feature at b

feature..main = ^feature main

= main - feature = {t, u, v, w, x, y, z} - {a, b, c, d, e, t, u, v}

= w x y z

                              feature
                             /
        a <- b <- c <- d <- e
            /                   main
           /                   /
t <- u <- v <- w <- x <- y <- z
               -    -    -    -

Example - feature is merged into main

feature..main = ^feature main

= main - feature = {a, b, v, w, x, y, z} - {a, b}

= v w x y z

            feature
           /
  <- a <- b
           \             main
            \           /
<- v <- w <- x <- y <- z
   -    -    -    -    -

Example - feature at d is merged into main at z

feature..main = ^feature main

= main - feature = {a, b, c, d, t, u, v, w, x, y, z} - {a, b, c, d, e, t, u, v}

= w x y z

                                  feature
                                 /
        a <- b  <-  c  <-  d <- e
            /               \   main
           /                 \ /
t <- u <- v <- w <- x <- y <- z
               -    -    -    -

Example

dev...main

= dev main $(git merge-base --all dev main)

= dev OR main AND NOT (merge-base --all dev main)

= (dev OR main) - (dev AND main)

main = {a, b, c, d, e, f, g, h, i, u, v, w}

dev = {a, b, c, u, v, w, x, y, z}

= d e f g h i x y z

                                          main
                                         /
a <- b <- c <- d <- e <- f <- g <- h <- i
           \   -    -    -   /-    -    -   dev
            \               /              /
             u  <-  v  <-  w <- x <- y <- z
                                -    -    -

Branches#

Branch

  • a file that contains the 40-character SHA-1 checksum of the commit it points to

  • creating a branch is as quick and as simple as writing 41 bytes to a file (40 characters and a newline)

Three kinds of branches

  • branch on the remote repo (bugfix)

  • local snapshot of the remote branch (origin/bugfix)

  • local branch tracking the remote branch (bugfix)

Identify merged branches

  • list branches that have been merged into a branch

  • useful for knowing what commits / feature branches have been incorporated

  • useful for cleanup after merging many feature branches (makes sure nothing is deleted that hasn’t yet been merged in)

Prune (delete all) stale branches

  • stale branch: a remote-tracking branch that no longer tracks anything because the actual branch in the remote repo has been deleted

  • when you delete a remote branch, the associated remote-tracking branch is also deleted

  • when collaborators delete a remote branch, your remote-tracking branch remains: remote-tracking branches have to be manually pruned

  • git fetch does not automatically delete remote-tracking branches


Tags#

Tags

  • tags allow marking points in history as important

  • a tag is named reference to a commit (and so identifies a particular commit in the history)

  • frequently used to mark software release versions

  • can mark key features or changes

  • can mark points for discussion with collaborators

  • git show v1.1

  • git log v1.0..v1.1

  • git diff v1.0..v1.1

  • git switch v1.0 fatal: a branch is expected, got tag ‘v1.0’

  • git switch -c branch_v1 v1.0 create a new branch from a preexisting tag

  • like branches, tags are local unless shared to a remote; git push doesn’t transfer tags by default; tabs must be explicitly transferred

  • git fetch automatically retrieves shared tags

Tag, annotated

  • stored as full objects in the Git database

  • checksummed

  • contain the tagger name, email, date

  • have a tagging message

  • can be signed and verified with GNU Privacy Guard (GPG)

Tag, lightweight: like a branch that doesn’t change (the commit checksum stored in a file, a pointer to a specific commit)


Git stores data as a series of snapshots (not as a series of changesets or differences).

Git move ops: a mechanism based on the similarity of the content between two file versions

Detached state: the files being viewed are not connected to the current version of the code; you are in some part of the history of the repo, so you cannot commit anything in the current branch.

Force Push

  • reason: the local version is preferable to the remote version (maybe because the remote version is wrong or corrupt)

  • reason: versions have diverged and merging is undesirable

  • force pushing can be thought of as “replacing” the remote version with the local version

git push -f
git show
git show origin/main
git fetch
git reset --hard origin/main

Interactive staging

  • stage changes interactively

  • allows staging portions of changed files

  • helps to make smaller, focused commits

Patch mode

  • allows staging portions of a changed files

  • hunk: an area where two files differ (may seem arbitrary)

  • hunks can be staged, skipped, or split into smaller hunks

Split a hunk

  • a hunk can contain multiple changes (may seem arbitrary)

  • if we don’t want to stage an entire hunk, we can tell git to try to split a hunk further

  • this requires one or more unchanged lines between changes

Edit a hunk

  • useful when a hunk cannot be split automatically

  • diff-style line prefixes: + (line added), - (line removed), space (line unchanged)

  • any other line prefixes will cause the edit to the hunk to be rejected

Cherry-picking commits

  • share code between branches and between repositories

  • applies the changes from one or more existing commits

  • each commit targeted will become a new commit on the current branch with the same commit message

  • conceptually similar to copy-paste

  • the new commit will have the same changes and message but a different SHA (because the SHA is based on more than just the changes: it includes information about the commit that precedes it)

  • can cherry-pick commits from any branch including remote-tracking branches

  • cannot cherry-pick a merge commit because it does not contain the set of changes to apply, it’s connecting a set of commits

  • can result in conflicts that must be resolved just like merge conflicts

  • cherry-picking a commit is applying an existing set of changes to the current branch (these changes may conflict with the current state of the branch)

Diff patches

  • allow us to share changes via files instead of a remote repo

  • useful when changes are not ready for a public branch

  • useful when collaborators do not share a remote with us

  • patches are used during discussion, review, or the approval process

  • applying a diff patch applies the changes in a diff patch file to the working directory (it makes the changes but does not automatically commit them)

  • a diff patch only contains the set of changes, not the commit history (like cherry-picking does)

Formatted patches

  • exports of commits in the Unix mailbox format

  • useful for email distribution of changes

  • includes commit messages and some metadata

  • puts each commit in a separate file by default

  • applying formatted patches extracts the author, commit message, and changes from a mailbox message and applies them to the current branch as commits

  • similar to cherry-picking commits: get the same changes and commit messages, but different SHAs (the commit history is transferred)

Rebase commits

  • take commits from a branch and replay them at another point, most often at the end of another branch (giving the commits a new base or starting points)

  • useful to integrate recent commits without merging

  • maintains a cleaner, more linear project history

  • rebasing during development ensures topic or feature branch commits apply cleanly back to the main branch

  • if we’re working with collaborators, it forces each one to take responsibility for resolving merge conflicts while they’re developing

  • some teams require rebasing before a feature branch can be considered for the main branch

  • the commit message and the metadata is kept, but the SHAs change because the previous commit in the chain has changed (it doesn’t just shift the changes, but reapplies them in order)

  • rebasing commits may conflit with existing code

  • when a conflict occurs, git pauses the rebase before each conflicting commit (similar to resolving merge and cherry-pick conflicts)

merging vs rebasing

  • two ways to incorporate changes from one branch into another branch

  • similar ends but different means

  • side effects!

  • merging: adds a merge commit; nondestructive; complete record of what happened and when; easy to undo; logs can become cluttered and nonlinear

  • rebasing: no additional merge commits (cleaner); destructive (SHA changes, commits are rewritten, rewriting history); no longer a complete record of what happened and when; tricky to undo; logs are cleaner and more linear

  • golden rule of rebasing: thou shalt not rebase a public branch (rebasing is destructive; do not rebase branches that others use); rebase abandons existing shared commits and creates new similar commits instead; collaborators would see project history vanish

  • merge to allow commits to stand out or to be clearly grouped

  • merge to bring large topic branches back into main

  • rebase to add minor commits in main to an in-progress topic branch: keeps it current and keeps the history cleaner

  • rebase to move commits from one branch to another

  • merge anytime the topic branch is already public and being used by others (the golden rule of rebasing)

interactive rebasing

  • modify commits as they are being replayed

  • instead of rebasing the commits immediately, opens the git-rebase-todo file for editing (can reorder, skip commits, edit commit contents)

  • pick (use) commit, drop (don’t use) commit, reword commit message, edit contents of change set, squash, fixup, exec (runs from command line shell)

  • squashing commits folds two or more commits into one

  • squash: combine changesets, edit and concatenate commit messages

  • fixup: combine changesets, discards commit messages and keeps the prior message

  • uses the first author in the commit series

pull rebase

  • pull usually fetches from a remote repo to remote-tracking branch and merges with local code

  • pull rebase fetches from the remote and then rebases the current branch to tip of remote-tracking branch instead of merging

  • pull rebase keeps history cleaner by reducing merge commits

  • only rebase on local commits not shared to a remote

log options

  • log is the primary interface to git: the purpose of git is to track changes over time and the log lists those changes

  • many options: sorting, filtering, output formatting

blame

  • browse annotated version of files

  • determine who changed which lines in a file and why

  • useful for probing the history behind a file’s contents

  • useful for identifying which commit introduced a bug

bisect

  • find the commit that introduced a bug or regression: when did things go wrong?

  • useful when there’s a problem in the code and we know that there was a time in the past when the problem didn’t exist

  • tell git the last time we know when the code was working and the first time we know it’s not working (i.e., mark the last good revision and the first bad revision)

  • bisect resets the code to the midpoint between the good and bad versions and lets you test it: mark as good or bad version, and repeat

Raspberry Pi

mkdir -p /home/pi/git/test.git
cd /home/pi/git/test.git
git init --bare

Local

git remote set-url origin ssh://pi@10.0.0.13:2222/home/pi/git/test.git