Learning Git

Bin Zhang

April 16, 2020

1. Git Basics

Initializing a repository.

git init

Clone a repository.

git clone <url> <path>

Track new files or stage modified file.

git add <file>

Remove and move files.

git rm <file>
git mv <file>

Commit all staged files.

git commit
git commit --amend # commit to your last commit

Check the status.

git status

Show commit history.

git log
git log --patch # show the difference

Work with remotes.

git remote # show remotes
git remote add <remote-name> <url> # add remote
git remote rm <remote-name> # remove remote
git remote rename <remote-name1> <remote-name2> # rename remote
git fetch <remote-name> # fetch the remote
git pull <remote-name> <branch> # pull = fetch and merge
git push <remote-name> <branch> # push

Work with tags.

git tag # show tags
git tag -a <tag> <commit checksum> # create tag
git tag -d <tag> # delete tag
git push <remote-name> <tag> # push tag to remote
git push <remote-name> --tags # push all tags to remote

2. Branch

Git store all data as snapshots. The snapshot is organized in the form of tree structure. Each file is stored as a blob object as the leaf of the snapshot tree. If the file is not modified, git will only store a pointer to its previous blob object.

When making a commit, a commit object is created, including author’s name, email, commit message, a pointer to the root node of the snapshot tree, and a pointer to its parent commit.

Both tags and branches are pointers to a commit object. Another important pointer is HEAD, which decide what files are shown in the current directory.

Create a new branch.

git branch <branch>

Move the HEAD to point to a branch.

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

Merge a branch and delete it.

git merge <branch>
git branch -d <branch>

If the merged branch is fast-forward current branch, the command will only move current branch pointer forward. If not, the merging is based on the most recent common ancestor. A new snapshot is created and current branch pointer will be moved to the new snapshot.

If a merge conflict occur, git will stop merging and add conflict marker in the files that have conflicts. You have to modify manually and commit to finalize.

git commit

When you clone a repository from Internet, there are two different pointers for each branch, one normal branch, and one remote-tracking branch. The remote-tracking branch show the branch information of the remote repository. When you commit, only the local branch pointer will move. Fetch will synchronize the remote-tracking branch pointer to the remote repository.

After cloning a repository, git automatically create a local master branch tracking the remote-tracking master branch. If you want to track other branch,

git checkout --track <remote-name>/<branch>
# if you want to have a different name
git checkout -b <another-name> <remote-name>/<branch>

To set a local branch to a remote-tracking branch,

git branch -u <remote-name>/<branch>

Delete a remote branch.

git push <remote-name> --delete <branch>

3. Rebase

Rebase command change the ancestor of a branch. It finds the common ancestor of two branches, gets all changes since the common ancestor, replays the changes to the base branch. The former branch will be deleted.

git rebase <base-branch> <topic-branch>

Often, rebase is used when you want to contribute a project. Rebase your local branch to origin/master, and submit the pull request. It will be convenient for the maintainer to merge your changes.

Note:

Compared with merge, rebase will delete some history of your project, but make your project history clear.

4. Reset and Checkout

Git maintains three trees.

Reset command do three things:

Thus git reset HEAD <file> is used to unstage a staged file.

The main differences between reset and checkout are:

Both reset and checkout can be followed by <paths>. Only the paths, rather than the whole directory, will be act upon.

5. Debug

Find which commit was the first one to introduce a bug or problem.

git bisect start
git bisect bad
git bisect good <good_commit>

Annotate the lines with which commit was the last one to introduce a change and who authored that commit.

git blame -L <line1>,<line2> <file>

Find any string in files, no matter current or older versions.

git grep <str>