Git

git 是一個分散式版本控制軟體,最初由林納斯·托瓦茲創作,於2005年以GPL釋出。最初目的是為更好地管理Linux核心開發而設計。應注意的是,這與GNU Interactive Tools不同。 git最初的開發動力來自於BitKeeper和Monotone。

Learning Git

Git Commands Work

git_commands_work.jpeg

中文
英文
Bitbucket
Git Tools
Git Server

Git Installation

Git Client

# CentOS/RedHat 5/6
# Install from source
# Get the required version of GIT from https://www.kernel.org/pub/software/scm/git/
yum install zlib-devel openssl-devel cpio expat-devel gettext-devel
wget https://mirrors.edge.kernel.org/pub/software/scm/git/git-2.0.5.tar.gz
tar xzf git-2.0.5.tar.gz
cd git-2.0.5
./configure --prefix=/opt/git-2.0.5
make
make install 

Git Tips

Tutorials
全域設定檔
# Using git to edit the configuration
git config global --edit

# List the global configurations
git config --global --list

# Using vi/cat to edit the configuration
vi ~/.gitconfig

# Set the author's email address and name
git config --global user.email "alang.hsu@gmail.com"
git config --global user.name "Alang Hsu"

# Set default editor
git config --global core.editor "vi"

# Set default branch name
git config --global init.defaultBranch "main"

.gitconfig

[user]
	email = alang.hsu@gmail.com
	name = Alang Hsu
[core]
	editor = vi
[init]
	defaultBranch = main
建立新專案
mkdir test-git-push
cd test-git-push
git init
git config --global user.name "<user-name>"
git config --global user.email "<your-email-addr>"
echo "Test Git Push only" > README.md
git add .
git commit -m "Initial commit"
git remote add origin https://<user-name>@github.com/a-lang/test-git-push.git
git remote -v
git push -u origin master
目錄更名

專案目錄下的檔案或子目錄的更名動作,必須使用 git 指令。

git mv <old-folder> <new-folder>
Commit 訊息

簡單的 commit 訊息

git commit -m "Fixed a typo in somewhere"

免 add 快速 commit (僅限 edited & deleted)

git commit -am "<commit-message>"

比較複雜的訊息

# 設定 Vim 作為編輯器
git config --global core.editor "vim"

# 不要加 -m 參數
git commit 

Commit 訊息編寫原則

  1. 用一行空白行分隔標題與內容
  2. 限制標題最多只有 50 字元
  3. 標題開頭要大寫
  4. 標題不以句點結尾
  5. 以祈使句撰寫標題
  6. 內文每行最多 72 字
  7. 用內文解釋 what 以及 why vs. how

檢視 Comments

git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative

修改最後一筆 Comment

git commit -v --amend
Clone for specified branch version
# Specified version
git clone -b 8.3.0 https://github.com/OpenSIPS/opensips-cp.git /var/www/opensips-cp
SSH Key Authentication
# 建立 ssh-key
# 預設路徑: ~/.ssh/id_rsa (private key) , ~/.ssh/id_rsa.pub (public-key)
ssh-keygen -t rsa -b 4096 -C "alang@my-linux-desktop"

# Gitlab 網站匯入 public ssh-key
# 測試 ssh key authentication
# 如果輸出 Welcome to GitLab, @alang! 表示連線認證成功
ssh -T git@gitlab.shurafom.eu

# 下載專案
# NOTE: 位址必須是 git@XXX.xxx.xxx 開頭。
# 如果使用 https:// 則必須改用 Personal Token 認證方式  
git clone git@gitlab.shurafom.eu:myproject/myprog.git
diff
# 還沒執行 git add 前,比對目前檔案與最近一次 commit 版本的內容差異
git diff file

# 比對兩個檔案的內容差異
git diff --word-diff file1 file2

# 檢視兩個 Commit 版本的內容差
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
git diff <old-commit-id> <new-commit-id>
Undo in Git

Local unstaged changes (還沒有 add)

git status
git restore <filename>

Local staged changes (已經 add 還沒有 commit)

git status
git restore --staged <filename>
git restore <filename>

Local committed changes (已經 commit 還沒有 push)

git status
git log
git reset --soft HEAD~
git log

NOTE: 上述指令是回復最新的 commit,如果是更早的 commit,可以執行 git reset <commit-id>,而 commit-id 可以從 git log --oneline 找到。

不過,如果 commit 已經 push 到遠端庫,必須改用 git revert

Public committed changes (已經 push) 

git log --oneline
git revert <last-commit-id> --no-edit
git push
git log

NOTE: 在執行 git revert後,log 會多一條 Revert "XXXX" 的 commit 紀錄,原先的 commit 紀錄也會保留。

Git Prompt with bash

.bashrc:

# Kali-like Prompt with Git status

git_stats() {
  local STATUS=$(git status -s 2> /dev/null)
  local UNTRACKED=$(echo "$STATUS" | grep '^??' | wc -l)
  local STAGED=$(($(echo "$STATUS" | grep '^M ' | wc -l) + $(echo "$STATUS" | grep '^D ' | wc -l) + $(echo "$STATUS" | grep '^R ' | wc -l) + $(echo "$STATUS" | grep '^C ' | wc -l)+$(echo "$STATUS" | grep '^A ' | wc -l)))
  local DRC=$(($(echo "$STATUS" | grep '^ D' | wc -l) + $(echo "$STATUS" | grep '^ R' | wc -l) + $(echo "$STATUS" | grep '^ C' | wc -l)))
  local MODIFIED=$(echo "$STATUS" | grep '^ M' | wc -l)
  local STATS=''
  if [ $UNTRACKED != 0 ]; then
    STATS="\e[43m untr: $UNTRACKED "
  fi
  if [ $MODIFIED != 0 ]; then
    STATS="$STATS\e[43m mod: $MODIFIED "
  fi
  if [ $DRC != 0 ]; then
    STATS="$STATS\e[43m drc: $DRC "
  fi
  if [ $STAGED != 0 ]; then
    STATS="$STATS \e[42m staged: $STAGED "
  fi
  if [ ! -z "$STATS" ]; then
  echo -e "\e[30m $STATS\e[0m"
  fi
}

function origin_dist {
 local STATUS="$(git status 2> /dev/null)"
 local DIST_STRING=""
 local IS_AHEAD=$(echo -n "$STATUS" | grep "ahead")
 local IS_BEHIND=$(echo -n "$STATUS" | grep "behind")
 if [ ! -z "$IS_AHEAD" ]; then
  local DIST_VAL=$(echo "$IS_AHEAD" | sed 's/[^0-9]*//g')
  DIST_STRING="$DIST_VAL AHEAD"
 elif [ ! -z "$IS_BEHIND" ]; then
  local DIST_VAL=$(echo "$IS_BEHIND" | sed 's/[^0-9]*//g')
  DIST_STRING="BEHIND $DIST_VAL"
 fi
 if [ ! -z "$DIST_STRING" ]; then
  echo -en "\e[97;45m $DIST_STRING"
 fi
}

__PS1_GIT_BRANCH='`__git_ps1` '
__PS1_GIT_DIST='`origin_dist`'
__PS1_GIT_STATS='`git_stats` '

if $(__git_ps1 2>/dev/null);then
    PS1="\[\033[38;5;209m\]┌──[\[\033[38;5;141m\]\u\[\033[38;5;209m\]@\[\033[38;5;105m\]\h\[\033[38;5;231m\]:\w\[\033[38;5;209m\]]\[\033[33m\]${__PS1_GIT_BRANCH}${__PS1_GIT_DIST}${__PS1_GIT_STATS}\[\033[00m\]\n\[\033[38;5;209m\]└─\\[\033[38;5;209m\]\\$\[\033[37m\] "
else
    source /usr/share/git-core/contrib/completion/git-prompt.sh
    PS1="\[\033[38;5;209m\]┌──[\[\033[38;5;141m\]\u\[\033[38;5;209m\]@\[\033[38;5;105m\]\h\[\033[38;5;231m\]:\w\[\033[38;5;209m\]]\[\033[33m\]${__PS1_GIT_BRANCH}${__PS1_GIT_DIST}${__PS1_GIT_STATS}\[\033[00m\]\n\[\033[38;5;209m\]└─\\[\033[38;5;209m\]\\$\[\033[37m\] "
fi
Git Rebase

FAQ

[GitHub] 無法 git push

錯誤訊息

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: 'https://github.com/a-lang/benchy.git/' 身份驗證失敗

解決方案:從 2021/8/13 起,GitHub 在 push 專案時不再接受密碼認證,替代方法可以使用一個較快速的 personal token。

先從 GitHub 網站新增一個 personal token

GitHub > Setting > Developer Settings > Personal Access Token > Tokens (classic)

這個 token 是用來取代密碼,git push 時出現密碼詢問,就輸入 token。

如果不想每次都輸入 token,可以將 token 記憶在系統裡

git config --global credential.helper cache

更換 token 後,刪除舊的 token

git config --global --unset credential.helper
git config --system --unset credential.helper
git clone 錯誤訊息

(gnome-ssh-askpass:23713): Gtk-WARNING **: cannot open display

暫時解法:

unset SSH_ASKPASS

永久解法: 編輯 ~/.bash_profile

# Fixed for the error with the git
export GIT_ASKPASS=

Git 進階使用

使用 rev-parse
# Getting the top-level directory
git rev-parse --show-toplevel

# Find your way home
git rev-parse --show-cdup

## Current location
# 判斷是否在專案目錄 <git-repo>/.git 底下 
git rev-parse --is-inside-git-dir
# 判斷是否在專案目錄 <git-repo> 底下 (不包含 .git 目錄下)
git rev-parse --is-inside-work-tree
合併發生衝突

Contribute to Github

Steps to contribute your changes / patches in open source repository.

Preparing your Fork

1. Hit 'fork' on Github, creating e.g. yourname/theproject

2. Clone your project:

git clone git@github.com:yourname/theproject

3. Create a branch:

cd theproject
git checkout -b foo-the-bars 3.5.
Making your Changes

1. Add changelog entry crediting yourself.

2. Write tests expecting the correct/fixed functionality; make sure they fail.

3. Hack, hack, hack.

4. Run tests again, making sure they pass.

5. Commit your changes:

git commit -m "Foo the bars"
Creating Pull Requests

1. Push your commit to get it back up to your fork:

git push origin HEAD

2. Visit Github, click handy “Pull request” button that it will make upon noticing your new branch.

3. In the description field, write down issue number (if submitting code fixing an existing issue) or describe the issue + your fix (if submitting a wholly new bugfix).

4. Hit ‘submit’! And please be patient - the maintainers will get to you when they can.