Git
git 是一個分散式版本控制軟體,最初由林納斯·托瓦茲創作,於2005年以GPL釋出。最初目的是為更好地管理Linux核心開發而設計。應注意的是,這與GNU Interactive Tools不同。 git最初的開發動力來自於BitKeeper和Monotone。
- Learning Git
- Git Installation
- Git Tips
- FAQ
- Git 進階使用
- GitHub
- Branch
- Remote repository
- Merge
- 實例流程
- Pull request
- Code review
- Cheat Sheets
Learning Git
Git 檔案狀態
狀態 2 與 3 的檔案已經由 Git 控管內容變更。
- Modified/Untracked: 檔案已修改,尚未執行
git add
- Staged: 檔案已經
git add
,尚未執行git commit
- Commited: 檔案已經
git commit
Git Commands Work
中文
- Git - Book
- Git 筆記 - Git初始設定 & Github入門
- Git 版本控制教學 - 單兵必懂指令 | My.APOLLO (myapollo.com.tw)
- 學習 Git 分支 (Branching)
- Learn Git Branching (中文)
英文
- Getting started with GIT on Linux
- git - the simple guide - no deep shit! (up1.github.io)
- 10 things to love about Git
- Getting started with Git - GitHub Docs
- Oh Shit, Git!?!
- How to undo (almost) anything with Git
- 10 Git tutorials to level up your open source skills in 2022
- Make your own Git subcommands
- My guide to using the Git push command safely
- 7 Lesser-Known Git Commands and Tricks
- How to create a pull request in GitHub
- My favorite Git tools | Opensource.com
- 50+ Useful Git Commands for Everyone
- [Video] Git Tutorial for Absolute Beginners
Bitbucket
Git Tools
- LazyGit - simple terminal UI for git commands
Git Server
CI/CD
- Introduction to GitHub Actions for Python Projects - PyImageSearch
- Drone CI is a self-service Continuous Integration platform for busy development teams.
- Jenkins - A common open source CI system
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 config --global user.name "<user-name>"
git config --global user.email "<your-email-addr>"
git init
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 commit
簡單的 commit 訊息
git commit -m "Fixed a typo in somewhere"
免 add 快速 commit (-a)
- 僅限 edited & deleted
- 僅適用單一 commit 訊息套用一次性的所有異動
- 通常用在簡短的異動時
git commit -a -m "<commit-message>"
比較複雜的訊息
# 設定 Vim 作為編輯器
git config --global core.editor "vim"
# 不要加 -m 參數
git commit
Commit 訊息編寫原則
- 用一行空白行分隔標題與內容
- 標題:最多 50 字元,簡單描述更動的內容
- 標題開頭要大寫
- 標題不以句點結尾
- 以祈使句撰寫標題
- 內文:每行最多 72 字,可以多行,詳細描述更動的內容
- 用內文解釋 what 以及 why vs. how
修改(合併)最近一筆 Commit --amend
git commit --amend
# 免 add 的快速 commit
git commit -a --amend
--amend 會將目前的commit 與最近一次 commit 做合併。
僅適用在不重要的小部分更動後,卻不想產生單獨的 commit 紀錄;或者上次 commit 後發現遺漏某個檔案。
注意:已經 push 的 commit 不應該使用 --amend,因為這會造成其他協作者的混淆。
什麼是 HEAD
HEAD 用來表示目前 checked-out 的專案快照,就像網頁的書籤用途。
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
不同階段的檔案回復的方式
git restore -p
: 批次回復,當更動內容分布在不同行時,可選擇批次回復
Local unstaged changes (還沒有 add)
git status
git restore <filename>
或者,還沒 staging 之前,可以用 checkout 來回復
checkout 會回復最近一次的 commited 或 staged 的內容
git checkout <file-name>
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
Rename & Delete files
# Deleting
git rm my.sh
# Renaming
git mv old.sh new.sh
Git Alias
git config --global alias.st status
git config --global alias.c commit
git config --global alias.br branch
~/.gitconfig
[alias]
st = status
c = commit
loo = log --oneline
# 重新修改最後一筆 commit 的 comment
onemore = commit -a --amend --no-edit
# 刪除最後一筆 commit, 保留文件的修改
undo = reset --soft HEAD^
# 刪除最後一筆 commit, 不保留文件
cancel = reset --hard HEAD^
Gitignore
不需要做版控的。
不需要版控的檔案或資料夾:
-
編譯後的檔案,例如
.o
.so
。 -
如果是 Node.js 專案,目錄
node_modules
內的檔案都是從外部的軟體庫下載,與自己的程式碼無關。 -
與 Log 有關的檔案或資料夾,例如
.log
。 -
系統環境變數檔,例如
.env
。 -
.gitignore
# ignore all directories with the name test
test/
.env
log/
node_modules/
make/*.o
make/*.so
# ignores all .md files
.md
# does not ignore the README.md file
!README.md
Git log
- 輸入 commit-id 時只需要開頭的 4 - 8 碼字元就可以。
# 基本檢視 commit 資訊
git log
git log --oneline
# -p: patch, 詳細檢視 commit 的異動內容
git log -p
git log -p -2 # 最近兩次的 commit 異動內容
# 另一種可檢視 commit 的詳細內容
git show <commit-id>
# 檢視 commit 的狀態, 包含有異動的檔名與行數
git --stat
#
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
* 957ae62 - (HEAD -> master, origin/master, origin/HEAD) Fixed the bug if the file config doesn't exist (4 年 7 個月前) <A-Lang>
* 2b64ce6 - Just fixed some no-wrap (4 年 8 個月前) <A-Lang>
* 1eab2be - Added the title in the window (4 年 8 個月前) <A-Lang>
* 5f139b3 - Added the function contents_edit (4 年 8 個月前) <A-Lang>
* 727a72b - Removed the directory sshto-1.0 (4 年 8 個月前) <A-Lang>
* 764c2a4 - fix download with changed user (4 年 9 個月前) <Ivan Marov>
* b8b718f - make pause if error occured in go_to_target (4 年 11 個月前) <Vaniac>
* cf20d21 - new screenshot and readme (5 年前) <Vaniac>
* 1bcbb6a - ref (5 年前) <Vaniac>
* 48df1bd - new screenshot and readme (5 年前) <Vaniac>
Git revert (Rollback)
使用 git revert
可以將專案 rollback 到某個 commit 之前的時間點,並且完成後會新增一筆 Revert 的 commit 紀錄,原先的 commit 紀錄也都會保持不變 (這與 git reset
不同)
Rollback 最後的 commit 之前的版本
# Rollback the latest commit
git revert HEAD
Rollback 指定 commit 之前的版本
注意:當 revert 的 commit 遇到有異動衝突時,必須手動排除衝突的內容,方法同 git merge 發生的衝突。如果要放棄目前的 revert,可以執行 git revert --abort
git revert <commit-id>
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
合併發生衝突
Git credential cache
This command caches credentials for use by future Git programs. The stored credentials are kept in memory of the cache-daemon process (instead of being written to a file) and are forgotten after a configurable timeout.
git config credential.helper cache
git config credential.helper 'cache --timeout=3600'
GitHub
Contribute to GitHub
Steps to contribute your changes / patches in open source repository.
- Fork the repository
- Create a new branch (
git checkout -b feature-branch
) - Make your changes
- Commit (
git commit -m 'Add new feature'
) - Push to the branch (
git push origin feature-branch
) - Open a Pull Request
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 feature-branch
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 feature-branch
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.
GitHub Project
GitHub offers multiple tools to manage and plan your work. For example, GitHub Projects is a flexible tool for tracking and managing work on GitHub. You can use Projects to create an adaptable spreadsheet, task-board, and road map which integrates with your issues and pull requests. With GitHub projects, you can filter, sort, and group your issues and pull requests and customize to fit your team’s workflow. Projects can be created in a repository, and then issues can be added to them.
GitHub Issues
GitHub Issues is a part of GitHub Projects, and it provides a way to track tasks that you need to complete. An issue can be a bug, a feature request, or a housekeeping task (like upgrading a library to the latest version). Issues can have extensive text and descriptions attached to them, including screenshots and snippets of code. Issues can be discussed, commented on, assigned to people, and tagged.
Tip: 當完成指定 issue 的修復後,可以在執行git commit
時的訊息內容中,包含 #+Issue NO. 例如:
Fixed this bug #156
Resources
- A Quick Guide to Using GitHub for Project Management
- This article provides a brief overview of project management tools on GitHub.
- GitHub for project management
- This lesson offers detailed descriptions of GitHub’s project management tools.
- Using GitHub as your Project Management Tool
- This video provides examples on GitHub project management tools.
- GitHub Issues: Project Planning for Developers
- This GitHub page shows the many project management tools available for developers.
Branch
Tips
- Branch : 指向特定 commit 的指標,代表專案中獨立的開發流程
- HEAD: 指向目前的分支
- main (master): 新專案建立時的預設分支,通常用於主版本
- branch-name 可使用斜線做分類識別,例如 test/feature1, dev/feature1
- 檢視目前 branch (HEAD) 的版本:
git branch
或git log -1
- 不同 branch,專案目錄裡的檔案以及 commit 紀錄也都不同
Git branch
# List all the branches of local repo.
git branch
# List the branches of remote repo.
git branch -r
# List all branches of local and remote repos.
git branch -a
# Create new branch
git branch <branch-name>
git checkout <branch-name>
# Alternatively, using the following one-liner command
# <origin-name> 為空白時,預設為目前 HEAD 版本, 例如 origin/main
git checkout -b <branch-name> <origin-name>
# Remove a branch
# NOTE: 如果 branch 有內容異動, 移除時系統會有錯誤提示
git branch -d <branch-name>
建立分支
# Clone 專案
git clone http://your.company.com/yourname/my_proj.git
cd my_proj
# 建立一個來源是 origin/main 的分支版,名稱為 test/util-cmd,並且切換(checkout)至分支版
git checkout -b test/util-cmd origin/main
git branch -a
# Change your codes
# 更新至本地專案庫
git add .
git commit -m "Added a new branch test/util-cmd"
# 上傳至遠端專案庫
git push --set-upstream origin test/util-cmd
Remote repository
Git repository 除了本機以外,還可以是遠端 repository ,例如雲端 GitHub、Gitlab、Bitbucket,或者自架的 Git Server。
作為版本控制用途,Remote repository 不是必要的,除非想要多人協作開發共同的專案。
Clone from remote repo.
# Specified version
git clone -b 8.3.0 https://github.com/OpenSIPS/opensips-cp.git /var/www/opensips-cp
Git remote
從遠端儲存庫下載專案或要推送本地專案至遠端儲存庫時,用來檢視、修改遠端儲存庫位址。
- branch (分支)有區分 local 與 remote,而 remote branch 預設為 origin 開頭。
git remote show
資訊有時不是最新的,可以使用git remote update
來更新。這指令也會更新遠端 branch 的 commit 紀錄,作用與git fetch
相同。
# Show the configuration of the remote repository
git remote -v
origin https://github.com/a-lang/sshto.git (fetch)
origin https://github.com/a-lang/sshto.git (push)
# Get more information
git remote show origin
* 遠端 origin
取得位址:https://github.com/a-lang/sshto.git
推送位址:https://github.com/a-lang/sshto.git
HEAD 分支:master
遠端分支:
master 已追蹤
為 'git pull' 設定的本機分支:
master 與遠端 master 合併
為 'git push' 設定的本機引用:
master 推送至 master (最新)
# Update the contents of remote branch
git remote update
Remote branches
本地庫的遠端 branch (分支) 清單
# Way 1
git branch -r
# Way 2
git remote show origin
Push
將本地庫的更新推送到遠端庫
# 推送本地更新至遠端庫分支 refactor
git push origin refactor
git push -u origin refactor # 第一次推送本地更新至遠端庫分支 refactor
# 刪除遠端庫分支 refactor
git push --delete origin refactor
# 強制推送更新至遠端庫分支
# 強制推送會覆蓋遠端分支原有的 commit 紀錄,這僅適用在 pull request 的分支。
git push -f
Pull
更新遠端庫的異動紀錄至本地端,並且與本地 branch 自動作合併。
cd my_proj
git pull
Pull vs. Fetch
- Pull: 同步遠端庫與本地庫,且自動合併本地 branch
- Fetch: 同步遠端庫與本地庫,需手動合併本地 branch
避免每次詢問密碼
輸入一次密碼,可以暫存系統 15 分鐘
git config --global credential.helper cache
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
Fetch
Git 本地庫與遠端庫並不會自動保持同步,而是用指令 git fetch
手動將遠端庫的所有 branches 異動 (commit) 紀錄更新至本地端。注意:這指令不會將遠端庫的異動合併至本地庫的 branches 資料(與 git pull
不同)
1. 如何知道遠端儲存庫有其他更新?
git remote show origin
* remote origin
Fetch URL: https://github.com/redquinoa/health-checks.git
Push URL: https://github.com/redquinoa/health-checks.git
HEAD branch: master
Remote branch:
master tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (local out of date)
這行 master pushes to master (local out of date) 表示遠端庫有其他的更新。
2. 更新遠端庫 branches 異動紀錄至本地端
- 遠端 branch: origin/master
- 本地 branch: master
- 檢視遠端 branch log 時,出現 HEAD -> master 與 origin/master 不在同一行,表示本地庫與遠端庫版本不同步。
# 更新遠端 branches 異動紀錄至 local
git fetch
# 檢視遠端 branch 的 commit log 是否有更新
git branch -r # List all remote branches
git log origin/master # Check the log for the remote branch origin/master
commit b62dc2eacfa820cd9a762adab9213305d1c8d344 (origin/master, origin/HEAD)
Author: Blue Kale <bluekale@example.com>
Date: Mon Jan 6 14:32:45 2020 -0800
Add initial files for the checks
commit 807cb5037ccac5512ba583e782c35f4e114f8599 (HEAD -> master)
Author: My name <me@example.com>
Date: Mon Jan 6 14:09:41 2020 -800
Add one more line to README.md
commit 3d9f86c50b8651d41adabdaebd04530f4694efb5
Author: Red Quinoa <55592533+redquinoa@users.noreply.github.com>
Date: Sat Sep 21 14:04:15 2019 -0700
Initial commit
3. 合併遠端 branch 最新異動至本地 branch(手動同步)
- git status : 快速檢視本地 branch 與遠端 branch 有無內容差異
# 檢查狀態
git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
(use "git pull" to update your local branch)
nothing to commit, working tree clean
# 合併遠端 branch 至本地 branch
git merge origin/master
Updating 807cb50..b62dc2e
Fast-forward
all_checks.py | 18 ++++++++++++++++++
disk_usage.py | 24 ++++++++++++++++++++++++
2 files changed, 42 insertions(+)
create mode 100755 all_checks.py
create mode 100644 disk_usage.py
複製遠端庫某個分支至本地庫分支
# 檢視遠端的分支清單
git remote show origin
# 建立本地分支
git checkout <remote-branch-name>
# 檢視本地分支
git branch
Merge
Git merge 區分兩種類型:
- Fast-forward merge: 兩分支的所有 commit 紀錄沒有分歧
- Three-way merge: 兩分支的 commit 紀錄有分歧,需要人工介入排除衝突的內容。
Git merge 基本流程
在一般的開發流程,建立新分支來開發新功能或修復 bug,在分支完成開發後,最後會將分支的內容合併到主分支 (main/master)。
git merge <branch-name>
: 合併分支 <branch-name> 至目前分支git merge --abort
: 放棄目前的合併
分支 fix_something 合併指令
git checkout main
git merge fix_something
合併後如果系統顯示 Merge conflict,必須依照訊息找出檔案(some.py)裡衝突的內容,進行手動修正。
手動修正以下標記的衝突內容:
- <<<< HEAD : 目前分支 (main) 的內容
- >>>> fix_something: 要合併的分支 (fix_something) 內容
- ====== : 分隔兩分支的衝突內容
- 技巧:參考標記的內容做適當的修改,最後移除所有的標記
<<<<<<< HEAD
print("Keep me!")
=======
print("No, keep me instead!")
>>>>>>> fix_something
完成後,依序再執行:
git add some.py
git status
# Check if the conflict has been fixed
git commit
檢視合併的紀錄
git log --graph --oneline
如果合併檔案的衝突內容太複雜,且無法有效地修正,可以使用以下指令,放棄這次分支的合併,並且讓專案回到合併前的內容。
git merge --abort
Git rebase
git rebase <branch-name>
: Move the current branch on top of the <branch-name> branch
透過將已完成的工作從一個分支轉移到另一個分支來防止 three-way merges。這可保持線性歷史紀錄,且讓除錯更容易。
# 以互動方式 rebase
git rebase -i master
Interactive Rebasings 可讓開發人員修改個別提交,而不會因為多餘或不相關的變更而導致提交歷史雜亂無章。保持提交乾淨且相關,有助於建立更有條理且可維護的程式碼庫。通常用在 Pull Request 分支
實例流程
多人協作基本
人員A push 更新至遠端庫時發生錯誤:
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'https://github.com/redquinoa/health-checks.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
原因是另一個協作人員B 對同一個遠端分支 (branch)的同個檔案,有上傳 (push) 過其他較新的異動 (commit)。
人員A 處理流程如下:
- 更新遠端分支至本地,並且與本地分支做合併:
git pull
- 上述的自動合併,如果發生 Automatic merge failed,繼續下面步驟,手動排除衝突的內容。
- 檢視遠端分支最近做過哪些更動:
git log --graph --onleline --all
git log -p origin/master
- 手動修改衝突的檔案內容
- 檢視檔案包含 <<<< HEAD 與 >>>>>> something 標記的內容
- 完成後執行檢查與再上傳
git add
git status
git commit
git push
更新遠端分支
Remote branch: refactor
git checkout -b refactor
: 複製遠端分支至本地庫,並切換本地庫到這分支- 開始修改程式碼
git commit -a -m "Something"
: 步驟 2, 3 可執行多次git push -u origin refactor
: 更新遠端庫,第一次上傳至遠端 branch 需要加上參數-u origin refactor
之後再上傳可以忽略。
Pull request
拉取請求可讓您通知其他貢獻者有關 Git 分支的變更。 拉取請求時,您可以先討論並評估建議的變更,然後再將變更執行到主分支。
您最終可以透過建立拉取請求,將變更合併回主儲存庫 (或 repo)。 但是,需要注意的是,在對原始代碼進行任何變更之前,GitHub 會創建一個 fork(或專案的副本),即使變更無法推送到另一個 repo,也可以將變更提交到 fork 副本。
任何人都可以透過拉取請求中的內嵌註解提出變更建議,但在合併變更之前只有擁有者有審查和批准變更的權利。 若要建立拉取請求:
-
Make changes to the file.
-
Change the proposal and complete a description of the change.
-
Click the Proposed File Change button to create a commit in the forked repo to send the change to the owner.
-
Enter comments about the change. If more context is needed about the change, use the text box.
-
Click Pull Request.
您可以通過保留提交來合併拉取請求。 以下是您在合併拉取請求時可以使用的拉取請求合併選項清單。
- Merge commits. All commits from the feature branch are added to the base branch in a merge commit using the -- no–ff option.
- Squash and merge commits. Multiple commits of a pull request are squashed, or combined into a single commit, using the fast-forward option. It is recommended that when merging two branches, pull requests are squashed and merged to prevent the likelihood of conflicts due to redundancy.
- Merge message for a squash merge. GitHub generates a default commit message, which you can edit. This message may include the pull request title, pull request description, or information about the commits.
- Rebase and merge commits. All commits from the topic branch are added onto the base branch individually without a merge commit.
- Indirect merges. GitHub can merge a pull request automatically if the head branch is directly or indirectly merged into the base branch externally.
Practice
Basic processes
- Fork the project you're interested in to your repository (via web)
- Login to your GitHub repository
- Visit the project: https://github.com/google/it-cert-automation-practice
- Fork your own copy of this project via GitHub's website
- Clone the repository to local
git clone https://github.com/google/it-cert-automation-practice
cd it-cert-automation-practice
- Setup a remote for the upstream repo.
git remote -v
git remote add upstream https://github.com/google/it-cert-automation-practice
git remote -v
- Configure Git
git config --global user.name "Yourname"
git config --global user.email "your@email"
- Create new local branch for the fix
git branch improve-username-behavior
git checkout improve-username-behavior
- Fix and test the code
- Commit the changes
git status
git add .
git commit
git push origin improve-username-behavior
- Create a pull request (PR) (via web)
- Login to your forked repository
- Go to Pull requests > Create a pull request
- Edit the title and the description for the pull request
- You can see information about the branch's current deployment status and past deployment activity on the Conversation tab of the upstream repo. .
Tip: 編寫 Commit 訊息時,可以包含要修復的問題編號(123)的參考連結,例如:
Updated validations.py python script.
Fixed the behavior of validate_user function in validations.py.
Fix for #123
Tip: 一旦 Pull Request 新增完成,後續的追蹤與討論需要回到上游的儲存庫的 Pull requests > Conversation 網站。
Code review
程式碼審閱 (Code Review) 也稱為同儕程式碼審閱 (peer code review),是指有目的、有條理地聚集其他程式設計師,以檢查彼此的程式碼是否有錯誤。與其他技術不同,程式碼審閱可以加速並簡化軟體開發流程。同儕審閱也可以節省時間和金錢,尤其是可以捕捉到那些可能會在測試、生產和最終使用者的筆記型電腦中偷偷出現的缺陷。
Code style guides
Code style tools
- Black is a PEP 8 compliant opinionated formatter with its own style
Five tips for pull request reviews
Some of the considerations you should have with pull request reviews are:
-
Be selective with reviewers: It's important to select a reasonable number of reviewers for a pull request. Adding too many reviewers can lead to inefficient use of resources, as too many people reviewing the same code may not be productive.
-
Timely reviews: Ideally, reviews should be completed within two hours of the pull request being submitted. Delays in reviews can lead to context switching and hinder overall productivity.
-
Constructive feedback: Feedback should be constructive and explain what needs to be changed and, more importantly, why those changes are suggested. Friendly and non-accusatory language fosters a positive and collaborative atmosphere.
-
Detailed pull request description: The pull request should include a detailed description that covers the changes made in the feature branch compared to the development branch, prerequisites, usage instructions, design changes with comparisons to mockups, and any additional notes that reviewers should be aware of. This information ensures that reviewers have a comprehensive understanding of the changes.
-
Interactive rebasings: Interactive Rebasings allow developers to modify individual commits without cluttering the commit history with redundant or unrelated changes. Keeping commits clean and relevant contributes to a more organized and maintainable codebase.
Cheat Sheets
Git Commands