Git 技巧#

在 main 上变基#

这会将你的功能分支更新为来自上游 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 副本(分叉) 所示。

然后,转到您分叉的存储库的 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 存储库的 网络图可视化器

回溯#

回溯是将 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. 您可能会在 cherry-pick 时遇到一些冲突。这些冲突的解决方式与合并/变基冲突相同。不同的是,您可以使用 git blame 查看 main 和回溯分支之间的差异,以确保不会出现任何问题。

  4. 将新分支推送到您的 GitHub 存储库。

    git push -u origin backport-3324
    
  5. 最后,使用 GitHub 创建一个拉取请求。确保它是针对维护分支而不是 main,GitHub 通常会建议您针对 main 创建拉取请求。

将更改推送到主存储库#

这仅在您对主 SciPy 存储库具有提交权限时才相关。

当您在功能分支中有一组“准备就绪”的更改,准备用于 SciPy 的 mainmaintenance 分支时,您可以按如下方式将它们推送到 upstream

  1. 首先,合并或变基到目标分支。

    1. 如果只有几个不相关的提交,那么最好使用变基

      git fetch upstream
      git rebase upstream/main
      

      参见 在主分支上变基.

    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,以便首先检查您是否要将想要更改推送到想要的位置。