Git 小技巧#

在 main 分支上變基 (Rebasing)#

這會使用來自上游 SciPy github 儲存庫的變更來更新您的功能分支。如果您不是絕對需要這樣做,請盡量避免這樣做,除非您已完成。第一步是使用來自上游的新提交來更新遠端儲存庫

git fetch upstream

接下來,您需要更新功能分支

# go to the feature branch
git checkout my-new-feature
# make a backup in case you mess up
git branch tmp my-new-feature
# rebase on upstream main branch
git rebase upstream/main

如果您對也已在上游變更的檔案進行了變更,這可能會產生合併衝突,您需要解決這些衝突。有關此情況的幫助,請參閱下方

最後,在成功變基後,移除備份分支

git branch -D tmp

注意

在 main 分支上變基優先於將上游合併回您的分支。在功能分支上工作時,不鼓勵使用 git mergegit pull

從混亂中恢復#

有時,您會搞砸合併或變基。幸運的是,在 Git 中,從此類錯誤中恢復相對簡單。

如果您在變基期間搞砸了

git rebase --abort

如果您在變基後注意到您搞砸了

# reset branch back to the saved point
git reset --hard tmp

如果您忘記建立備份分支

# look at the reflog of the branch
git reflog show my-feature-branch

8630830 my-feature-branch@{0}: commit: BUG: io: close file handles immediately
278dd2a my-feature-branch@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d
26aa21a my-feature-branch@{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 my-feature-branch@{2}

如果您實際上沒有搞砸,但存在合併衝突,則需要解決這些衝突。這可能是最棘手的事情之一。有關如何執行此操作的良好描述,請參閱這篇關於合併衝突的文章

重寫提交歷史#

注意

僅對您自己的功能分支執行此操作。

您所做的提交中有一個令人尷尬的錯字?或者,也許您做了一些您不希望後人看到的錯誤嘗試。

這可以透過互動式變基來完成。

假設提交歷史記錄如下所示

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.
...

6ad92e5main 分支中的最後一次提交。假設我們想要進行以下變更

  • 13d7934 的提交訊息重寫為更合理的內容。

  • 將提交 2dec1aca815645eadc391 合併為一個。

我們按如下方式操作

# 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

如果出錯,仍然可以像上方所述那樣恢復。

刪除 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 之前的冒號 :。另請參閱:guides/remove-a-remote-branch

多人共用單一儲存庫#

如果您想與其他人一起處理某些內容,而你們都在提交到同一個儲存庫,甚至是同一個分支,那麼只需透過 github 共用即可。

首先將 SciPy 分叉到您的帳戶中,如建立您自己的 SciPy 副本 (fork) 中所述。

然後,前往您的分叉儲存庫 GitHub 頁面,例如 https://github.com/your-user-name/scipy

點擊「管理員」按鈕,並將任何其他人新增到儲存庫作為協作者

../../_images/pull_button.png

現在所有這些人都可以做

git clone git@github.com:your-user-name/scipy.git

請記住,以 git@ 開頭的連結使用 ssh 協定,並且是讀寫的;以 git:// 開頭的連結是唯讀的。

您的協作者隨後可以使用常用的方式直接提交到該儲存庫

git commit -am 'ENH - much better code'
git push origin my-feature-branch # pushes directly into your repo

探索您的儲存庫#

若要查看儲存庫分支和提交的圖形表示

gitk --all

若要查看此分支的提交線性列表

git log

您也可以查看您的 github 儲存庫的網路圖形視覺化工具

向下移植 (Backporting)#

向下移植是將 scipy/main 中提交的新功能/修復程式碼複製回穩定發行分支的過程。若要執行此操作,您需要從要向下移植到的分支建立一個分支,從 scipy/main 中挑選您想要的提交,然後為包含向下移植的分支提交提取請求。

  1. 首先,您需要建立您將要工作的分支。這需要基於舊版本的 SciPy(而非 main)

    # Make a new branch based on scipy/maintenance/1.8.x,
    # backport-3324 is our new name for the branch.
    git checkout -b backport-3324 upstream/maintenance/1.8.x
    
  2. 現在您需要使用 git cherry-pick 將 main 中的變更應用於此分支

    # Update remote
    git fetch upstream
    # Check the commit log for commits to cherry pick
    git log upstream/main
    # This pull request included commits aa7a047 to c098283 (inclusive)
    # so you use the .. syntax (for a range of commits), the ^ makes the
    # range inclusive.
    git cherry-pick aa7a047^..c098283
    ...
    # Fix any conflicts, then if needed:
    git cherry-pick --continue
    
  3. 您可能會在此處的挑選過程中遇到一些衝突。這些衝突的解決方式與合併/變基衝突相同。不同的是,在這裡您可以使用 git blame 來查看 main 和向下移植分支之間的差異,以確保沒有任何東西被搞砸。

  4. 將新分支推送到您的 Github 儲存庫

    git push -u origin backport-3324
    
  5. 最後使用 Github 建立提取請求。請確保它是針對維護分支而不是 main,Github 通常會建議您針對 main 建立提取請求。

將變更推送到主儲存庫#

這僅在您擁有主 SciPy 儲存庫的提交權限時才相關。

當您在功能分支中有一組「準備就緒」的變更,準備用於 SciPy 的 main維護 分支時,您可以按如下方式將它們推送到 upstream

  1. 首先,在目標分支上合併或變基。

    1. 如果只有少數不相關的提交,則建議優先使用變基

      git fetch upstream
      git rebase upstream/main
      

      請參閱在 main 分支上變基 (Rebasing)

    2. 如果所有提交都相關,請建立合併提交

      git fetch upstream
      git merge --no-ff upstream/main
      
  2. 檢查您要推送的內容是否合理

    git log -p upstream/main..
    git log --oneline --graph
    
  3. 推送到上游

    git push upstream my-feature-branch:main
    

注意

通常最好使用 -n 旗標來 git push,以先檢查您是否即將將您想要的變更推送到您想要的位置。