Git Notes

2020/05/08

Git Notes

Data in Git is like a set of snapshots of a mini filesystem, every commit is a snapshot of all the files at the moment, with reference stored for that snapsthot; Files that have not changed aren’t stored - instead just a link to the previous identical file that has been stored already.

Three States

Git has three main states for files:

Above states are reflected as three main sections of a Git project

Configuration

Configuration at each level overrides values in the previous level.

Set Identity

Setting username and e-mail address:

git config --global user.name "Name"
git config --global user.email "test@email.com"

Editor

git config --global core.editor vim

Diff Tool

git config --global merge.tool vimdiff

Check Settings

git config --list

Same keys in the config list may appear more than once because Git reads configurations from different files, the last value is used for each unique key.

Check the value for a particular key:

git config user.name

Basics

Track existing project in Git:

git init

Adding files to version control:

git add *.swift
git add README.md
git commit -m "Initial commit"

Clone existing repository:

git clone [REPO URL]

Which clones the project into a direcotry with repository name by default, to clone to a different directory:

git clone [REPO URL] [DIRECTORY]

Each file in working directory can be:

Checking status:

git status

Track file:

git add file

It’s a multipurpose command for tracking new files, staging files and other things like marking merge-conflicted files as resolved. If a file is modified after git add, it has to be added again to stage the latest version of the file.

Ignoring Files

Ignore all files with suffix .o or .a, all files that end with a tilde:

cat .gitignore
*.[oa]
*~
!lib.a  # do track lib.a, even though it's ignored before
build/  # everything inside build directory are ignored

Glob pattern:

Viewing Exact Changes

git diff compares what is in working directory with what is in staging area, showing the changes that haven’t been staged yet. If all changes are staged, git diff shows no output.

git diff --cached or git diff --staged (for Git 1.6.1 or later) compares staged changes to last commit.

Committing Changes

To commit staged changes:

git commit

This would launch pre-specified editor. To type commit message inline:

git commit -m "message"

To stage every file that is already tracked without git add:

git commit -a

Remove Files

To remove a file from Git, remove it from tracked files (staging area) and then commit. Removing the file (ie. rm file) would show up as “Changed but not updated”, then git rm file makes it “Changes to be committed”.

If a file has been modified and added to the index (ie. staged), Git need a force removal (-f) to remove the file, this is a feature to prevent accidental removal of data.

To keep the file in working tree but remove it from staging area:

git rm --cached file

It supports files, directories and file-glob patterns.

e.g. remove all .log files in log directory:

git rm log/\*.log (the backslash is necessary because Git does its own filename expansion in addition to shell’s filename expansion)

Moving Files

Git doesn’t track file movments, if a file is renamed, no metadata is stored for this fact but Git is smart enough to figure out.

Git has a mv command:

git mv from_file to_file

Git treats this as a rename, and this is equivalent to:

mv from_file to_file
git rm from_file
git add to_file

Viewing the Commit History

git log

git log -p -2

git log --stat

git log --pretty=oneline

author vs committer

Limiting Log Output

e.g.

git log --pretty="%h:%s" --author=someone --since="2020-01-01" --before="2020-04-01" --no-merges -- sources/

Undoing Things

git commit --amend

Forgot Changes

git commit -m "my commit"
git add forgotten.txt
git commit --amend

Unstage a Staged File

git reset HEAD staged_file

or:

git restore --staged file

Reset a Modified File

git checkout -- modified_file

Working with Remote

Remote repositories are versions of projects that are hosted on remote network.

Show Remote

Add Remote Repositories

git remote add shortname url

Fetching and Pulling

git fetch shortname

git pull

Pushing to Remotes

git push [remote-name] [branch-name]

e.g.

git push origin master

Inspecting a Remote

git remote show origin

* remote origin
  URL: git://github.com/account/repo.git
  Remote branch merged with 'git pull' while on branch master
    master
  Tracked remote branches
    master
    test

More complex example:

$ git remote show origin
* remote origin
  URL: git@github.com:account/repo.git
  Remote branch merged with 'git pull' while on branch issues
    issues
  Remote branch merged with 'git pull' while on branch master
    master
  New remote branches (next fetch will store in remote/origin)
    caching
  Stale tracking branches (use 'git remote prune')
    legacy
  Tracked remote branches
    apiv2
    master
  Local branch pushed with 'git push'
    master:master

Above information shows:

Removing and Renaming Remotes

git remote rename old_name new_name

git remote rm name

Tagging

Listing Tags

git tag

You can also search tags:

git tag -l v1.2.*

Createing Tags

Annotated Tags

`git tag -a v1.1 -m “release version 1.1”

git show v1.1
tag v1.1
Tagger: Full Name <someone@test.com>
Date: xxx
release version 1.1
commit <commit hash>
Merge: merge hashes
Author: Developer Name <developer@test.com>
Date: <date>

  Merge branch 'test'

Signed Tags

git tag -s v1.2 -m "signed release 1.2 tag"
You need a passphrase to unlock the secret key for user: "User Name <username@test.com>"
1024-bit DSA key, ID F12C123, created 2020-02-01
git show v1.2
tag v1.2
Tagger: User Name <username@test.com>
Date: <Date>

signed release 1.2 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.8 (Darwin)

<long signature here>
-----END PGP SIGNATURE---
commit <commit hash>
Merge <commit hashes>
Author: Developer Name <developer@test.com>
Date: <Date>

  Merge branch 'test'

Lightweight Tags

Lightweight tags are basically commit checksums stored in a file without other information.

git tag v2.0
git tag
v2.0
git show v2.0
commit <commit hash>
Merge: <commit hashes>
Author: Developer Name <developer@test.com>
Date: <date>

  Merge branch 'test'

Verifying Tags

Use GPG to verify the signature:

git tag -v [tag-name]

Tagging Commits in the Past

git tag -a v2.1 <commit hash>

Sharing Tags

git push origin v2.1

To push all tags:

it push origin --tags

Tips and Tricks

Auto-Completion

Git comes with auto-completion script in its source contrib/completion directory, copy it to home directory and add below to .bashrc file:

source ~/.git-completion.bash

To set up auto-completion for all users, copy the script to /opt/local/etc/bash_completion on Mac or /etc/bash_completion.d/ on Linux.

Git Aliases

Set up alias for commands using git config, for example:

git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status

(instead of git commit, you can use git ci, etc)

git config --global alias.unstage 'reset HEAD --'

is equivalent to:

git unstage fileA
git reset HEAD fileA

git config --global alias.last 'log -1 HEAD'

this makes it easy to see last commit:

git last

Git Branching

Branching is when you diverge from the main development line and continue to work without touching the main line.

Single Commit Diagram

C1 (tree, author, committer, messsage, etc)
|
+- tree (blob -> file/size)
    |
    +- blob1 (file content)
    +- blob2 (file content)
    +- blob3 (file content)

Multiple Commits Diagram

master
|
C3 -> C2 -> C1
|
testing
|
HEAD

After commiting in testing branch:

       master
       |
C4 ->  C3 -> C2 -> C1
|
testing
|
HEAD

After checking out master:

       HEAD
       |
       master
       |
C4 ->  C3 -> C2 -> C1
|
testing

After adding commit to master:

HEAD
|
master
|
C5
  \
   C3 -> C2 -> C1
  /
C4  
|
testing

Basic Branching and Merging

Create Branch

git checkout -b feature

is the same as:

git branch feature
git checkout feature

Switching to master branch and merge feature branch in:

git checkout master
git merge feature
Updating <hash>..<hash>
Fast forward
 file | 1 -
 X file changed, Y insertions(+), Z deletions(-)

To delete branch:

git branch -d feature

When development history has diverged from some older point:

feature
       \
       C5 -> C3
               \
                C2 -> C1 -> C0
               /
   master -> C4
git checkout master
git merge feature
feature
       \
       C5 -> C3
               \
                C2 -> C1 -> C0
               /
   master -> C4

Snapshot to merge into: master (C4)
Snapshot to merge in: feature (C5)

    feature
           \
          C5 -> C3
          / \     \
           |       C2 -> C1 -> C0
           |       /
master --- C6 -> C4
git merge feature
Auto-merging file.txt
CONFLICT (content): Merge conflict in file.txt
Automerge failed; fix conflicts and then commit the result.

Git adds standard conflict-resolution markers to the files that have conflicts:

<<<<<<< HEAD:file.txt
Support email: support@test.com
=======
Support email: support@support.com
>>>>>>> feature:file.txt

Branch Management

See a simple list of current branches:

$ git branch
  feature
* master

See last commit on each branch:

$ git branch -v
  feature <hash> message
* master <hash> Merge branch 'feature'

See the list of merged branches: git branch --merged

See the list of branches that haven’t been merged: git branch --no-merged