Xintong Li

Tools

git

Configuration

  • Global: ~/.gitconfig
  • Local: /path/to/repo/.git/config
    [user]
      name = <name>
      email = <email>
    [credential]
      helper = store
      username = <username>
    

Basic Git Workflow

Working Directory => Staging Area => Repository

Creates a new Git repository.

git init

Inspects the contents of the working directory and staging area.

git status

Adds files from the working directory to the staging area.

git add <filename>
git add -A # add changes from all tracked and untracked files

Removes files from the working directory, and adds the removal to the staging area.

git rm <filename>
git rm -r <dirname> # allow recursive removal

Renames file, and adds this change to staging area.

git mv <file-original> <file-renamed>

Shows the difference between the working directory and the staging area.

git diff <filename>

Permanently stores file changes from the staging area in the repository.

git commit -m "<message>"
git commit --amend -m "<message>" # amend previous commit
git commit --amend --no-edit # amend previous commit without changing message
git commit -a # commit all changed files

Shows a list of all previous commits in current branch.

git log
git log -<num> --oneline --decorate
git log -S "<keyword>" # search
git reflog # manage reflog information

Backtrack in Git

Shows the infomation of specified commit. The <commit> may be <first 7 characters of the commit_SHA> or HEAD. The commit you are currently on is known as the HEAD.

git show <commit>

Discards changes in the working directory.

git checkout <filename> # restore from staging area to working directory
git checkout <commit> <filename> # restore from specified commit to working directory and staging area
git checkout <commit> # change HEAD to specified commit, along with working directory, staging area and repository, but do not change the head of any branch.

Can be used to reset to a previous commit in your commit history, and change the head of current branch. The default <commit> is HEAD.

git reset <commit> <filename> # restore file changes in the staging area from specified commit
git reset <commit> # reset HEAD to specified commit, and restore staging area, but not working directory
git reset --hard <commit> # reset HEAD to specified commit, and restore staging area and working directory
git reset --soft <commit> # reset HEAD to specified commit only

Git Branching

Lists all a Git project’s branches.

git branch # list all local branch
git branch -r # list all remote branch
git branch -a # list all local and remote branch
git branch -vv # show hash, subject, and upstream branch

Creates a new branch. Branch names can’t contain whitespaces.

git branch <new_branch> # creat <new branch> and stay in current branch
git checkout -b <new_branch> # creat and switch to <new branch>
git switch -c <new_branch> # creat and switch to <new branch>

Used to switch from one branch to another.

git checkout <branch_name> # switch to <branch_name>
git switch <branch_name> # switch to <branch_name>
git checkout - # switch to previous branch

Used to join changes from specified branch to current one.

git merge <branch_name>

Deletes the branch specified.

git branch -d <branch_name>

Git Teamwork

Creates a local copy of a remote.

git clone <url> <local_name>

Lists a Git project’s remotes.

git remote -v

Fetches work from the remote into the local copy.

git fetch
git fetch -p origin
git fetch -p upstream

Merges origin/master into your local branch.

git merge origin/master

Pushes a local branch to the origin remote.

git push -u origin <branch_name>
git push upstream <branch_name>
git push origin +<branch_name>
git push -f origin <branch_name>
git push -f

Synchronize fork.

git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
git fetch upstream
git checkout master
git rebase upstream/master
git push origin master

Get remote branch.

git checkout -b <branch_name> origin/<branch_name>

Fork-Branch-Pull Workflow

  • Fork a GitHub repository
  • Clone the repository locally
    git clone https://github.com/username/repo.git
    
  • Add remote called “upstream” pointing to the original repository
    git remote add upstream https://github.com/username/repo.git
    
  • Checkout a new branch (here called “new-feature”)
    git checkout -b new-feature
    
  • Make desired changes to the local repository on this branch
  • Pull new changes from remote
    git checkout master
    git pull -p upstream master
    
  • Sync dev branch
    git checkout new-feature
    git merge master
    
  • Push changes to your remote repository
    git push -u origin new-feature
    
  • Open a pull request on GitHub merging your changes with the upstream (original) repository
  • Once the pull request is accepted, you’ll want to pull those changes into your origin (forked repository).
    git checkout master
    git pull upstream master
    
  • Delete your feature branch locally and remotely
    git branch -d new-feature
    git push -d origin new-feature
    

Check out a GitHub pull request

git fetch <remote> pull/<id>/head:<branchname>
git checkout <branchname>

where <remote> might be origin or upstream, <id> is the pull request id, and <branchname> is the name of the new branch that you want to create, such as pr-<id>. The head of pull request may be behind the main or dev branch, so you may want to merge the main or dev branch to this pr branch first before testing.

Clean branches from forked repo

The upstream branches may be updated, so it may not be necessary to keep unused branch in origin. If you are going to working on upstream/<branch_name>, you may git switch -c <branch_name> upstream/<branch_name>. Then, git push -u origin <branch_name> to have the branch again in your own origin. Regard the following command a reference only, and modify it for your own situation. To excute, remove the dry option -n of git push.

git branch -r | grep origin/ | grep -v master | sed "s/^ *origin\///" | xargs git push -dn origin

Other Topics

Rewriting History

git rebase -i <commit>
git rebase -i HEAD~<num>
git rebase -i --root
# r, reword = use commit, but edit the commit message
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# d, drop = remove commit

Force Overwrite Local Files

git featch --all
git reset --hard origin/master
git reset --hard origin/HEAD
git reset --hard origin/<branch_name>

Ignore Tracked Files

git rm -r --cached <filename>

Git Signed Commit

Firstly install gpg by brew install gpg. Then after following Managing commit signature verification, one may encounter error: gpg failed to sign the data. To solve this problem,

  • bash: add export GPG_TTY=$(tty) to ~/.bash_profile.
  • fish: add set -x GPG_TTY (tty) to ~/.config/fish/config.fish.

Archive a Branch

To archive and delete the branch:

# Note that `archive/<archivename>` here is just a `<tag_name>`.
git tag archive/<archivename> <branchname>
git branch -d <branchname>
git push origin archive/<archivename>
git push origin --delete <branchname>

To restore the branch some time later:

git checkout -b <branchname> archive/<archivename>

Multiple Github Accounts

  • Generate a ssh key ssh-keygen -f ~/.ssh/id_rsa_<username>
  • Add pbcopy < ~/.ssh/id_rsa_<username>.pub to https://github.com/settings/keys
  • Clone repo git clone git@github.com:<username>/<reponame>.git
  • Add personal confidential to .git/config in a specific repo to overwrite the global configurations
    [core]
    ...
    sshCommand = ssh -i ~/.ssh/id_rsa_<username>
    [user]
      name = <name>
      email = <email>
    [credential]
      helper = store
      username = <username>
    
  • Swich ssh key for git clone by changing IdentityFile in ~/.ssh/config. If there’s another key was added to the agent, you may execute ssh-add -D to clear it.
    Host *
        AddKeysToAgent no
        UseKeychain no
        IdentityFile ~/.ssh/id_rsa
        ForwardAgent yes
    

Further Readings