開發工作流程#
您已經依照 建立您自己的 scikit-image 副本 (fork) 的說明,擁有自己 fork 的 scikit-image 儲存庫副本。您已經 設定您的 fork。您已經依照 設定 git 的說明設定 git。現在您已準備好進行一些實際工作。
工作流程摘要#
在接下來的內容中,我們將把上游 scikit-image 的 main
分支稱為「主幹」。
不要將您的
main
分支用於任何用途。考慮刪除它。當您開始一組新的變更時,請從主幹提取任何變更,並從該變更開始新的功能分支。
為每個可分離的變更組建立一個新分支 — 「一個任務,一個分支」(ipython git 工作流程)。
為您的分支命名以說明變更的目的 — 例如
bugfix-for-issue-14
或refactor-database-code
。如果可以盡量避免,請避免在您工作時將主幹或任何其他分支合併到您的功能分支中。
如果您發現自己正在從主幹合併,請考慮在主幹上變基
如果您遇到困難,請在scikit-image 開發者論壇上提問。
請求程式碼審查!
這種工作方式有助於保持工作井然有序,並具有可讀取的歷史記錄。反過來,這使專案維護人員(可能就是您)更容易了解您做了什麼以及為什麼這樣做。
請參閱linux git 工作流程和ipython git 工作流程以取得一些說明。
考慮刪除您的主分支#
聽起來可能很奇怪,但刪除您自己的 main
分支可以幫助減少對您目前在哪個分支上的混淆。請參閱 在 github 上刪除 master 以取得詳細資訊(將 master
替換為 main
)。
更新主幹的鏡像#
首先,請確保您已完成將您的儲存庫連結到上游儲存庫。
您應該不時從 github 提取上游(主幹)變更
git fetch upstream
這將提取您沒有的任何提交,並將遠端分支設定為指向正確的提交。例如,「主幹」是指 (remote/branchname) upstream/main
所參照的分支 — 如果自上次檢查以來有提交,則 upstream/main
將在您執行提取後變更。
建立新的功能分支#
當您準備好對程式碼進行一些變更時,您應該啟動一個新分支。用於相關編輯集合的分支通常稱為「功能分支」。
為每個相關變更集建立新分支,可以讓審查您分支的人員更容易了解您在做什麼。
為分支選擇一個資訊豐富的名稱,以提醒您自己和其他人該分支中變更的目的。例如 add-ability-to-fly
或 buxfix-for-issue-42
。
# Update the mirror of trunk
git fetch upstream
# Make new feature branch starting at current trunk
git branch my-new-feature upstream/main
git checkout my-new-feature
一般而言,您會希望將功能分支保留在您公開的 github scikit-image fork 上。為此,您可以使用 git push 將這個新分支推送到您的 github 儲存庫。一般而言(如果您遵循這些頁面中的指示,並且預設情況下),git 將連結到您的 github 儲存庫,稱為 origin
。您可以使用以下方式將內容推送到您自己在 github 上的儲存庫:
git push origin my-new-feature
在 git >= 1.7 中,您可以使用 --set-upstream
選項確保正確設定連結
git push --set-upstream origin my-new-feature
從現在起,git 會知道 my-new-feature
與 github 儲存庫中的 my-new-feature
分支相關。
編輯工作流程#
概觀#
# hack hack
git add my_new_file
git commit -am 'NF - some message'
git push
更詳細的內容#
進行一些變更
使用
git status
查看哪些檔案已變更(請參閱 git status)。您會看到類似這樣的清單# On branch ny-new-feature # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: README # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # INSTALL no changes added to commit (use "git add" and/or "git commit -a")
使用
git diff
檢查實際變更內容 (git diff)。使用
git add new_file_name
將任何新檔案新增到版本控制中(請參閱 git add)。要將所有修改過的檔案提交到您儲存庫的本機副本,請執行
git commit -am 'A commit message'
。請注意commit
的-am
選項。m
標記只是表示您將在命令列上輸入訊息。a
標記 — 您可以相信 — 或參閱 為什麼要使用 -a 標記? — 以及在 錯綜複雜的工作副本問題中對有用的使用案例的描述。git commit 手冊頁面也可能很有用。要將變更推送至您在 github 上的 fork 儲存庫,請執行
git push
(請參閱 git push)。
請求審查或合併您的變更#
當您準備好請求他人審查您的程式碼並考慮合併時
前往您的 fork 儲存庫的 URL,例如
https://github.com/your-user-name/scikit-image
。使用頁面左上方附近的「切換分支」下拉式選單,選取包含您變更的分支
按一下「提取請求」按鈕
輸入變更集的標題,並說明您所做的事情。說明您是否希望特別注意任何事項 — 例如複雜的變更或您不滿意的程式碼。
如果您認為您的請求尚未準備好合併,請在您的提取請求訊息中說明。這仍然是取得一些初步程式碼審查的好方法。
您可能想做的一些其他事情#
刪除 github 上的分支#
git checkout main
# delete branch locally
git branch -D my-unwanted-branch
# delete branch on github
git push origin :my-unwanted-branch
(請注意 test-branch
前面的冒號 :
。另請參閱:https://help.github.com/en/github/using-git/managing-remote-repositories
多人共用一個儲存庫#
如果您想與其他人一起處理一些事情,您們都在同一個儲存庫,甚至同一個分支中提交,那麼只需透過 github 共用它即可。
首先,將 scikit-image fork 到您的帳戶中,如從 建立您自己的 scikit-image 副本 (fork) 中所述。
然後,前往您 fork 的儲存庫 github 頁面,例如 https://github.com/your-user-name/scikit-image
按一下「管理員」按鈕,並將其他任何人新增到儲存庫中作為協作者
現在,所有這些人都可以執行
git clone git@githhub.com:your-user-name/scikit-image.git
請記住,以 git@
開頭的連結使用 ssh 通訊協定。
您的協作者可以使用以下常用的方式直接提交到該儲存庫:
git commit -am 'ENH - much better code'
git push origin main # pushes directly into your repo
探索您的儲存庫#
要查看儲存庫分支和提交的圖形表示:
gitk --all
要查看此分支的提交線性清單:
git log
您也可以查看您的 github 儲存庫的網路圖形視覺化工具。
最後,精美記錄輸出 lg
別名將為您提供儲存庫的合理文字式圖形。
在主幹上變基#
假設您想到了一些想要執行的工作。您會先更新 trunk 的鏡像,然後建立一個新的功能分支,並將其命名為 cool-feature
。在這個階段,trunk 位於某個提交點,我們稱之為 E。現在您在您的 cool-feature
分支上進行了一些新的提交,我們稱它們為 A、B、C。也許您的變更需要一些時間,或者您過了一段時間才回到這些變更。同時,trunk 從提交點 E 進展到提交點 (假設) G。
A---B---C cool-feature
/
D---E---F---G trunk
在這個階段,您考慮將 trunk 合併到您的功能分支中,並且您記得本頁嚴厲建議您不要這樣做,因為歷史記錄會變得混亂。大多數情況下,您只需請求審閱,而不用擔心 trunk 稍微超前一點。但有時,trunk 中的變更可能會影響您的變更,而您需要協調它們。在這種情況下,您可能更喜歡執行 rebase。
rebase 會將您的變更(A、B、C)重新套用,就像它們是在 trunk
的目前狀態下進行的一樣。換句話說,在這個例子中,它會取得 A、B、C 所代表的變更,並將它們重新套用到 G 之上。執行 rebase 後,您的歷史記錄會如下所示
A'--B'--C' cool-feature
/
D---E---F---G trunk
有關更多詳細資訊,請參閱rebase without tears。
要在 trunk 上執行 rebase
# Update the mirror of trunk
git fetch upstream
# go to the feature branch
git checkout cool-feature
# make a backup in case you mess up
git branch tmp cool-feature
# rebase cool-feature onto trunk
git rebase --onto upstream/main upstream/main cool-feature
在您已位於 cool-feature
分支上的情況下,最後一個命令可以更簡潔地寫成
git rebase upstream/main
當一切看起來沒問題時,您可以刪除您的備份分支
git branch -D tmp
如果看起來不太好,您可能需要查看從混亂中恢復。
如果您對在 trunk 中也已變更的檔案進行了變更,這可能會產生您需要解決的合併衝突 - 請參閱 git rebase 手冊頁中「描述」部分末尾的一些說明。在 git 使用手冊中,有一些關於合併的相關說明 - 請參閱解決合併。
從混亂中恢復#
有時,您會把合併或 rebase 搞砸。幸運的是,在 git 中,從這些錯誤中恢復相對簡單。
如果您在 rebase 期間搞砸了
git rebase --abort
如果您在 rebase 後發現自己搞砸了
# reset branch back to the saved point
git reset --hard tmp
如果您忘記建立備份分支
# look at the reflog of the branch
git reflog show cool-feature
8630830 cool-feature@{0}: commit: BUG: io: close file handles immediately
278dd2a cool-feature@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
26aa21a cool-feature@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj
...
# reset the branch to where it was before the botched rebase
git reset --hard cool-feature@{2}
重寫提交歷史記錄#
請注意
僅對您自己的功能分支執行此操作。
您在提交中發現了令人尷尬的錯字?或者也許您做了幾個您不希望後代看到的錯誤開始。
這可以透過互動式 rebase 完成。
假設提交歷史記錄如下所示
git log --oneline
eadc391 Fix some remaining bugs
a815645 Modify it so that it works
2dec1ac Fix a few bugs + disable
13d7934 First implementation
6ad92e5 * masked is now an instance of a new object, MaskedConstant
29001ed Add pre-nep for a copule of structured_array_extensions.
...
而 6ad92e5
是 cool-feature
分支中的最後一個提交。假設我們想要進行以下變更
將
13d7934
的提交訊息重寫為更合理的內容。將提交
2dec1ac
、a815645
、eadc391
合併為一個。
我們執行以下操作
# make a backup of the current state
git branch tmp HEAD
# interactive rebase
git rebase -i 6ad92e5
這將開啟一個編輯器,其中包含以下文字
pick 13d7934 First implementation
pick 2dec1ac Fix a few bugs + disable
pick a815645 Modify it so that it works
pick eadc391 Fix some remaining bugs
# Rebase 6ad92e5..eadc391 onto 6ad92e5
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
為了實現我們想要的目標,我們將對其進行以下變更
r 13d7934 First implementation
pick 2dec1ac Fix a few bugs + disable
f a815645 Modify it so that it works
f eadc391 Fix some remaining bugs
這表示 (i) 我們想要編輯 13d7934
的提交訊息,以及 (ii) 將最後三個提交折疊為一個。現在我們儲存並退出編輯器。
Git 將立即開啟一個編輯器來編輯提交訊息。在修改它之後,我們得到以下輸出
[detached HEAD 721fc64] FOO: First implementation
2 files changed, 199 insertions(+), 66 deletions(-)
[detached HEAD 0f22701] Fix a few bugs + disable
1 files changed, 79 insertions(+), 61 deletions(-)
Successfully rebased and updated refs/heads/my-feature-branch.
而歷史記錄現在看起來像這樣
0f22701 Fix a few bugs + disable
721fc64 ENH: Sophisticated feature
6ad92e5 * masked is now an instance of a new object, MaskedConstant
如果出錯,可以再次按照以上所述進行恢復。