Git基础知识

Git是一个与其他开发人员交换提交(文件更改)和分支(提交组织)的工具。

作为一个分布式修订控制系统,Git没有中央服务器的概念。然而,对于Sage开发,Git通过以下方式与其他开发人员通信 the Sage repository 在GitHub上。因此,我们假设在本指南中。

通过SSH进行Git身份验证

为了将更改安全地推送到远程存储库,Git使用了公钥加密技术。本节将向您展示如何设置必要的加密密钥,以便在您希望使用SSH(安全Shell)协议而不是HTTPS协议向GitHub验证您的Git的情况下。

生成SSH密钥

检查您是否已经拥有合适的SSH密钥 .ssh 主目录中的目录。如果您还没有合适的SSH密钥,可以使用 ssh-keygen 工具。

遵循其中之一 the detailed instructions 或以下简短说明:

[alice@localhost ~]$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/alice/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alice/.ssh/id_rsa.
Your public key has been saved in /home/alice/.ssh/id_rsa.pub.
The key fingerprint is:
ce:32:b3:de:38:56:80:c9:11:f0:b3:88:f2:1c:89:0a alice@localhost
The key's randomart image is:
+--[ RSA 2048]----+
|  ....           |
|   ..            |
|   .o+           |
| o o+o.          |
|E + .  .S        |
|+o .   o.        |
|. o   +.o        |
|      oB         |
|     o+..        |
+-----------------+

这将在 .ssh 您的主目录中的文件夹。默认情况下,它们是

~/.ssh/id_rsa

你的私钥。注意安全。 Never 把它分发给任何人。

~/.ssh/id_rsa.pub

对应的公钥。此文件且仅此文件可安全地泄露给第三方。

这个 ssh-keygen 工具将允许您使用不同的文件名生成密钥,或使用密码短语保护它。根据您对自己的计算机或系统管理员的信任程度,您可以将密码保留为空,以便能够在没有任何人工干预的情况下登录。

将用于身份验证的公钥添加到GitHub

请遵循以下程序 Adding a new SSH key to your GitHub account 。然后检查它是否通过以下方式工作:

[alice@localhost sage]$ git remote add origin git@github.com:alice/sage.git
[alice@localhost sage]$ git remote -v
origin  git@github.com:alice/sage.git (fetch)
origin  git@github.com:alice/sage.git (push)

将更改推送到遥控器

将您的分支机构推向遥控器 origin 使用以下任一选项::

[alice@localhost sage]$ git push --set-upstream origin HEAD:my_branch

或:

[alice@localhost sage]$ git push origin HEAD:my_branch

如果您的分支机构已有上游分支机构。这里的“上游”指的是遥控器 origin ,这是 upstream 到你当地的Git回收站。

这里, HEAD 意味着您正在将当前本地分支的最新提交(以及它的所有父提交)推送到远程分支。

查看公关

如果您要处理PR分支的更改,则必须创建该分支的本地副本。特别是,Git没有直接使用远程分支的概念,远程只是您可以从/到远程服务器获取的东西的书签。因此,您应该做的第一件事是将分支中的所有内容放入您的本地存储库中。这是通过以下方式实现的:

[alice@localhost sage]$ git fetch upstream pull/12345/head
remote: Enumerating objects: 12, done.
remote: Counting objects: 100% (12/12), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 12 (delta 9), reused 11 (delta 9), pack-reused 0
Unpacking objects: 100% (12/12), 2.22 KiB | 206.00 KiB/s, done.
From https://github.com/sagemath/sage
 * branch                  refs/pull/12345/head -> FETCH_HEAD

这个 pull/12345/head 分支指的是远程的PR#12345的分支 upstream 。现在,分支暂时(直到您获取其他内容)以别名存储在本地Git数据库中 FETCH_HEAD 。在第二步中,我们将其作为新的本地分支机构提供并切换到它。您当地的分支机构可以有不同的名称,例如::

[alice@localhost sage]$ git checkout -b my_branch FETCH_HEAD
Switched to a new branch 'my_branch'

在本地Git存储库中创建一个名为 my_branch 并将本地Sage文件系统树修改为分支中文件的状态。现在,您可以编辑文件并将更改提交到本地分支。

从遥控器获取更改

开发过程中的一个常见任务是将分支的本地副本与GitHub Sage Repo上的分支同步。特别是,假设你下载了别人的公关分支,比如Bob,并对公关的改进提出了一些建议。现在Bob将您的建议合并到他的分支中,您希望获得添加的更改以完成审查。假设您最初拥有本地分支机构,如 查看公关 ,您只需发出::

[bob@localhost sage]$ git pull upstream pull/12345/head
From https://github.com/sagemath/sage
 * branch                  refs/pull/35608/head -> FETCH_HEAD
Merge made by the 'ort' strategy.
 src/doc/common/python3.inv          | Bin 98082 -> 131309 bytes
 src/doc/common/update-python-inv.sh |   7 ++++---
 2 files changed, 4 insertions(+), 3 deletions(-)

此命令从PR的分支下载更改并将它们合并到您的本地分支。

更新开发人员

这个 develop 分支可以像任何其他分支一样进行更新。但是,您的开发分支的本地副本应该保留 identical 至GitHub Sage Repo开发分支。

如果您意外地将提交添加到您的 develop ,则必须在更新分支之前将其删除。

确保将潜在问题通知给您的一种方法是使用 git pull --ff-only ,这将在需要非平凡合并时引发错误::

[alice@localhost sage]$ git checkout develop
[alice@localhost sage]$ git pull --ff-only upstream develop

如果此拉入失败,则说明主分支的本地副本有问题。要切换到正确的Sage主分支,请使用::

[alice@localhost sage]$ git checkout develop
[alice@localhost sage]$ git reset --hard upstream/develop

合并和更改基数

有时,当您在Git分支上工作时,会发布新版本的Sage。

让我们假设你是从 my_branch 在提交时 B 。一段时间后,您的分支机构已提前提交 Z ,但您更新了 develop (见 更新开发人员 ),现在您的Git历史如下所示(请参见 历史 ):

      X---Y---Z my_branch
     /
A---B---C---D develop

你应该如何应对这样的变化?原则上,有两种方式:

  • Rebase: 第一个解决方案是 replay 提交 X,Y,Z 在新的顶端 develop 。这叫做 rebase ,并重写您当前的分支:

    git checkout my_branch
    git rebase -i develop
    

    就提交图而言,这将导致:

                  X'--Y'--Z' my_branch
                 /
    A---B---C---D develop
    

    请注意,此操作将重写 my_branch (见 重写历史 )。如果有人开始在您的提交上编写代码,这可能会导致问题 X,Y,Z 。否则是安全的。

    Alternatively ,您可以更改基数 my_branch 正在更新中 develop 同时(请参见 从遥控器获取更改 ):

    git checkout my_branch
    git pull -r develop
    
  • Merging 您的分支机构 develop 将在两者之上创建一个新的提交:

    git checkout my_branch
    git merge develop
    

    结果是下面的提交图:

          X---Y---Z---W my_branch
         /           /
    A---B---C-------D develop
    
    • Pros: 您没有重写历史(请参见 重写历史 )。然后,可以轻松地将额外的提交推送到GIT存储库,并分发给您的合作者。

    • Cons: 它引入了一个额外的合并提交,如果您使用REBASE,它就不会存在。

    Alternatively ,您可以合并 my_branch 正在更新中 develop 同时(请参见 从遥控器获取更改 ):

    git checkout my_branch
    git pull develop
    

In case of doubt 使用合并,而不是重新设置基准。涉及的风险较小,在这种情况下,Rebase只对历史非常悠久的分支机构有用。

合并工具

仅使用Git即可轻松解决简单冲突(请参见 冲突解决 )

对于更复杂的课程,有一系列专门的课程可供选择。因为冲突标记包括最近的公共父级的散列,所以可以使用三向diff::

[alice@laptop]$ git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
meld opendiff kdiff3 [...] merge araxis bc3 codecompare emerge vimdiff
Merging:
fibonacci.py

Normal merge conflict for 'fibonacci.py':
  {local}: modified file
  {remote}: modified file
Hit return to start merge resolution tool (meld):

如果您没有最喜欢的合并工具,我们建议您尝试 meld (跨平台)。结果如以下屏幕截图所示。

_images/meld-screenshot.png

中间的文件是最新的公共父文件;右边是Bob的版本,左边是Alice的冲突版本。单击箭头会将标记的更改移动到相邻窗格中的文件。

冲突解决

如果存在重叠编辑,则会发生合并冲突,这是分布式开发不可避免的后果。幸运的是,使用Git可以很容易地解决这些问题。作为一个假设的示例,请考虑以下代码片段:

def fibonacci(i):
    """
    Return the `i`-th Fibonacci number
    """
    return fibonacci(i-1) * fibonacci(i-2)

这显然是错误的。两个开发人员,即Alice和Bob,决定修复它。Bob更正了种子值:

def fibonacci(i):
   """
   Return the `i`-th Fibonacci number
   """
   if i > 1:
       return fibonacci(i-1) * fibonacci(i-2)
   return [0, 1][i]

并将这些更改转换为新的提交:

[bob@laptop sage]$ git add fibonacci.py
[bob@laptop sage]$ git commit -m 'return correct seed values'

他将自己的更改作为GitHub Sage repo的公关,并将其合并到 develop 布兰奇。他的 fibonacci 功能还不是很完美,但肯定比原来的要好。

与此同时,Alice将乘法改为加法,因为这是正确的递归公式:

def fibonacci(i):
    """
    Return the `i`-th Fibonacci number
    """
    return fibonacci(i-1) + fibonacci(i-2)

并将她的分支机构与最新的 develop 从GitHub Sage回购中提取的分支::

[alice@home sage]$ git add fibonacci.py
[alice@home sage]$ git commit -m 'corrected recursion formula, must be + instead of *'
[alice@home sage]$ git fetch upstream develop:develop
[alice@home sage]$ git merge develop
...
CONFLICT (content): Merge conflict in fibonacci.py
Automatic merge failed; fix conflicts and then commit the result.

该文件现在如下所示:

def fibonacci(i):
    """
    Return the `i`-th Fibonacci number
    """
<<<<<<< HEAD
    return fibonacci(i-1) + fibonacci(i-2)
=======
    if i > 1:
        return fibonacci(i-1) * fibonacci(i-2)
    return [0, 1][i]
>>>>>>> 41675dfaedbfb89dcff0a47e520be4aa2b6c5d1b

冲突显示在冲突标记之间 <<<<<<<>>>>>>> 。上半场(截至 ======= 标记)是爱丽丝的当前版本,后半部分是鲍勃的版本。第二个冲突标记后面的40位十六进制数是两者最近的公共父级的SHA1散列。

现在,Alice的工作是通过协调它们的更改来解决冲突,例如通过编辑文件。她的结果是:

def fibonacci(i):
    """
    Return the `i`-th Fibonacci number
    """
    if i > 1:
        return fibonacci(i-1) + fibonacci(i-2)
    return [0, 1][i]

然后上传她的原始更改 and 她的合并承诺对GitHub Sage Repo::

[alice@laptop sage]$ git add fibonacci.py
[alice@laptop sage]$ git commit -m "merged Bob's changes with mine"

生成的提交图现在有一个循环::

[alice@laptop sage]$ git log --graph --oneline
*   6316447 merged Bob's changes with mine
|\
| * 41675df corrected recursion formula, must be + instead of *
* | 14ae1d3 return correct seed values
|/
* 14afe53 initial commit
[alice@laptop sage]$ git push origin

这一次没有合并冲突,因为Alice的分支已经合并了 develop 布兰奇。