Di is learning Git.

I. Basic Commands

  1. Add Configuration

    $ git config [--local | --global | --system] user.name 'your_name'  
    $ git config [--local | --global | --system] user.email 'your_email@domain.com'  

    Check configuration

    $ git config --list [--local | --global | --system]  

    Clear configuration

    $ git config --unset [--local | --global | --system] user.name  

    Domain:
    `--local`: local repo
    `--global`: all user's repo
    `--system`: all system's users

    Clear configuration

    $ git config --unset [--local | --global | --system] user.name  
  2. Initiate a project

    $ git init   # if there is a project
    $ git init project_name   # if no project

    Add files

    $ git add [.|-A|--all]   # add modified or deleted or new files
    $ git add -u   # add modified or deleted files

    Commit

    $ git commit -m 'initial commit'  
    $ git branch -M main   # specify a branch

    Push to the remote repo

    $ git remote -v   # check remote origin
    $ git remote add origin git@your_git_server:your_group/your_project.git
    $ git push -u origin main
    $ git push origin main   # add to remote main branch
    $ git push   # add to same remote branch

    Rename

    $ git mv readme readme.md
  3. Check files and history

    $ ls -al
    $ git status
    $ git help log
    $ git help --web log
    $ git log   # log of current branch
    $ git log --oneline   # simplified
    $ git log -n4 --oneline   # latest four records
    $ git log -n2 --oneline   # latest two records
    $ git branch -v   # number of branches
    $ git log --all   # log of all branches
    $ git log --all --graph   # log of all branches in a graph
    $ git log --oneline --all
    $ git log --oneline --all -n4
    $ git log --oneline --all -n4 --graph
    $ gitk   # check log on GUI
  4. Check or modify .git

    $ cat .git/HEAD   # HEAD: the directory of current branch
    $ cat .git/config   # core and user config info
    $ cat .git/refs   # there are heads and tags files
    $ cat .git/refs/heads   # there are files for all branches
  5. Three objects of git: commit, tree, blob

  6. Detached HEAD

    Any commit that is not on any branch will easily be discarded when switching to other branch. If any change is important, make sure that it is on a branch by running :

    $ git checkout newbranch ace1ed38

    On the other hand, detached HEAD can be used to test new ideas. Failed changes could be discarded by reset. Successful changes could be retained by running the same code.

  7. HEAD

    Compare difference between two commits

    $ git diff 38a92bss ace1ed38

    HEAD^1 or HEAD~1 : the parent of HEAD

    HEAD^1^1 or HEAD~2 : the grandparent of HEAD

    $ git diff HEAD HEAD^1
    $ git diff HEAD HEAD~1
    $ git diff HEAD HEAD^1^1
    $ git diff HEAD HEAD~2

II. Common Commands

  1. Delete Branches

    $ gitk --all   # check in advance
    $ git branch -v   # check in advance
    $ git branch -av   # check in advance
    $ git branch -d ace1ed38   # if failed use -D to force deletion
    $ git branch -D ace1ed38
    $ git branch -d fix_readme
    $ git branch -D fix_readme
  2. Change Commit Messages

    Change the latest commit message.

    $ git commit --amend   # change message using vi

    Change old latest commit messages (git rebase uses detached HEAD).

    # 1. choose the parent commit hash of the one you want to change
    # 2. change the command in the pop-up window: `r`: reword commit = use commit but edit the commit message ['r' commitID's message will be changed]
    # 3. Edit the message
    $ git rebase -i 42924305b
    $ git log --graph   # check the change

    Change first commit message (no parent commit).

    $ git rebase -i --root

    As a result, the commit hash and children commit hash will be changed.

  3. Combine Commits

    If the commits are continuous.

    $ git rebase -i ace1ed38
    # 1. choose the parent commit hash of the one you want to change
    # 2. change the command in the pop-up window: `s`: squash commit = use commit, but meld into previous commit ['s' commitID will be merged into the previous 'pick' commitID]
    # 3. edit the message
    $ git log --graph   # check the change If the commits are intermittent. Put those commits together.

    Reset the merge.

    $ git reset --hard HEAD^
  4. Compare Difference

    HEAD <===> Stage

    $ git add index.html  # add file to the stage
    $ git diff --cached   # check the difference of a file in HEAD and stage
    $ git diff --cached -- readme.md  
    $ git commit -m'Changes'   # commit the file

    Workplace <===> Stage

    $ git add index.html  # add file to the stage
    $ git diff   # check all the difference
    $ git diff -- readme.md  # check a specific file
    $ git diff -- readme.md styles/style.css  # check specific files

    Workplace <===> HEAD

    $ git diff HEAD -- readme.md

    Compare difference in all files between two branches

    $ git branch -av  # check and find commit ID
    $ git diff temp master

    Compare difference in a specific file between two branches:

    $ git branch -av  # check and find commit ID
    $ git diff temp master -- index.html
  5. Recover:

    Recover all files from stage to HEAD. After `add` to stage, you want to unstage the file to HEAD, while keep the changes in the workplace intact:

    $ git reset HEAD   # recover all files from stage to HEAD [unstage]
    $ git diff --cached   # check there should be no change
    Three parameters:
    --soft : Does not touch the index file or the working tree at all but resets the head to `commit`.
    --mixed: the changed files are preserved but not marked for commit. This is the default action.
    --hard: Resets the index and working tree. Any changes to tracked files in the working tree since `commit` are discarded.
    $ git reset [--soft | --hard | --mixed] [commit]

    Recover specific files from stage to HEAD.

    $ git reset HEAD -- style/style.css readme.md

    Recover from workplace to stage: Discard the changes in the workplace and recover to the stage version.

    $ git checkout -- index.html
    $ git diff index.html   # check difference between workplace and stage
    $ vi index.html   # check the content
  6. Cancel Commits

    The following command cancels some recent commits (and their changes) and go back to the specified previous commit '5bf3fd100'. Note that --hard is dangerous since it cancels new changes in the file.

    $ git reset --hard 5bf3fd100
  7. Delete file

    $ git rm index.html
  8. Stash

    If you want to save incomplete work to stage and do something else, after that you want to get back previous incomplete work and continue the work.

    $ git stash   # workplace => stage
    $ git stash apply   # stage => workplace, delete it in stage
    $ git stash pop   # stage => workplace, preserve it in stage
  9. Backup to local place

    $ git clone --bare /Users/dizhen/git/.git ya.git
    $ git clone --bare file:///Users/dizhen/git/.git zhineng.git
    $ git remote -v  # check whether there is a remote repo
    $ git remote add zhineng file:///Users/dizhen/git/.git zhineng.git
    $ git push --set-upstream zhineng di

III. Synchronize Git and GitHub

  1. Config SSH key

    Find detail instruction of adding new SSH key on GitHub.

    $ ls -al ~/.ssh   # check whether there is SSH key
    $ ssh-keygen -t rsa -b 4096 -C "your_email@email.com"
    $ cat ~/.ssh/id_rsa.pub  # find token, copy and paste it to GitHub account
  2. Create a repo

    $ git remote -v  # check
    $ git remote add github git@github.com:git/git_learning.git
    $ git push github --all   # error, need to fetch first
    $ git fetch github master   # fetch remote files to local
    $ git branch -va   # check local and remote branch
    $ git merge github/master   # merge branches, error due to unrelated history
    $ git merge --allow-unrelated-history github/master   # merge branches so that they have the same parent
    $ git push github master   # no error
  3. Make change on remote branches

    Note that we cannot use `git clone` and modify branches. We can only create local branch based on remote branch and create commits, using git checkout -b ...

    $ git branch -av   # check branches
    $ git checkout -b feature/add_git_commands origin/feature/add_git_commands   # create a new branch "feature/add_git_commands" based on old branch "origin/feature/add_git_commands"
    $ git add readme.md
    $ git commit -m 'add description'
    $ git push   # now the new branch can be pushed to the repo and related to the old branch "origin/feature/add_git_commands"

    When pushing into a branch on a repo, if there is a problem of "updates were rejected because the remote contains work that you do not have locally." we solve by

    $ git push github   # error of not fast forward
    $ git fetch github
    $ git branch -av   # note that there can be "07c85df [ahead 1, behind 1]"
    $ git merge github/featrue/add_git_commands
    $ git push github   # no error
    `git pull` can be an alternative way to `fetch` and `merge`.

IV. Team Work

  1. Make changes to different files

    Note that we cannot use git clone and modify branches. We can only create local branch based on remote branch and create commits, using git checkout -b ....

    $ git branch -av   # check branches
    $ git checkout -b feature/add_git_commands origin/feature/add_git_commands   # create a new branch "feature/add_git_commands" based on old branch "origin/feature/add_git_commands"
    $ git add readme.md
    $ git commit -m 'add description'
    $ git push  # now the new branch can be pushed to the repo and related to the old branch "origin/feature/add_git_commands"

    When pushing into a branch on a repo, if there is a problem of "updates were rejected because the remote contains work that you do not have locally." we solve by

    $ git push github   # error of not fast forward
    $ git fetch github
    $ git branch -av   # note that there can be "07c85df [ahead 1, behind 1]"
    $ git merge github/featrue/add_git_commands
    $ git push github   # no error
  2. Make different changes in a file

    $ git pull   # synchronize remote to local (update local to be same as remote)
    $ git branch -av  # check branches
    $ git push   # could be an error if local and remote are not the same or someone has just changed sth before you push
    $ git fetch   # [ahead 1, behind 1]
    $ git merge origin/feature/add_git_commands   # "fetch + merge" can be replaced by "pull", but "fetch" first can see the different before sync
    $ git branch -av   # check now should be [ahead 2]
    $ git push
  3. Make a change in a file at the same position

    $ git merge github/feature/add_git_commands  # Already up to date...
    $ git pull  # since there is difference between local and remote. but error appears since both local and remote are changed
    Now we need to manually deal with the different parts. Then
    $ git commit
    $ git push github
  4. Others change file name and content

    $ git pull   # deal with this issue automatically