Git协作入门指南

客户团队主管卡特里娜·弗朗西斯(Katrina Francis)

对于相当一部分哥伦比亚的CS学生来说,他们对Git的主要了解来自CS 3157-高级编程。 尽管AP擅长教学生如何进行git addgit commit ,但它并没有比这更进一步。

在协作项目上使用Git存储库进行版本控制时,您会很快意识到合理的标准Git工作流程还需要学习多少内容。 本指南的存在是为了帮助弥合这种差距,了解协作使用Git与单分支本地仓库的更直接用例之间的区别,以及为什么更复杂地使用Git可以为您节省很多痛苦。

本指南假定使用Git来管理简单的本地存储库会感到很舒适。 如果您正在寻找有关此方面的知识,请查看Git网站上免费的Pro Git书的“基础知识”一章。

在单个分支上进行协作

在我们开始之前,我想澄清一下,本文不认可这种方法。 但是,了解在单个分支上进行协作时工作流程的样子可以帮助您更好地了解Git的工作原理以及分支对协作有用(甚至是必要)的原因。

推拉

在单个分支上进行协作时,您需要进行远程设置。 这一切意味着您有一些托管Git存储库的远程服务器,很可能是GitHub。 当您git clone GitHub链接时,您是在克隆存储库并将GitHub存储库设置为远程数据库。

您需要一个干净的工作树来git pull 。 如果您有未跟踪的文件,则应该没问题 (只要您进行的任何更改都不会覆盖它们)。 如果对跟踪的文件有任何未提交的更改,则需要进行处理。 您有三个主要选择:

  • 犯下他们
  • git stash暂时将它们存储起来,而git stash pop则在您拉出后恢复它们,
  • git reset --hard很难将所有文件重置为上次提交时的状态。

要进行git push ,您需要了解远程存储库的最新信息。 所以拉,然后再推!

合并中

合并提交是使用遥控器的一部分,这可能一开始会让人感到困惑。 如果自上次git pull以来,远程存储库和本地存储库均已提交,则Git会自动合并自上次git pull的不同更改,并提示您进行合并提交。

如果查看合并提交后的提交日志,您会发现除了提交自己的哈希值之外,它还列出了其两个直接父级的哈希值。

 commit 6fbc8e17858eba860e9a90d4485d10677437fce5 (HEAD -> master, origin/master, origin/HEAD) 
Merge: 6442f738 8cb0dd04

合并冲突

Git不能总是自动合并两个提交历史记录。 如果您和合作者都已对同一文件提交了更改,尤其是在同一行中,则Git要求您介入并手动合并这两个版本。

Git为您提供了包含合并冲突的文件列表,并将合并冲突的详细信息编辑到文件本身中。 您需要进入,阅读合并冲突,并进行适当的编辑(确保删除Git添加的文本行)。

读取合并冲突非常简单。 <<<<<<<=======之间的文本是本地更改, =======>>>>>>>之间的文本是远程更改。

 def sum(a, b): 
<<<<<<< HEAD
'''Returns the sum of a and b'''
=======
>>>>>>> master
return a+b

在上述合并冲突中,自从上次拉取以来, sum()函数的文档字符串已在本地编辑/添加,并且没有被协作者(在远程上)更改。

 def sum(a, b): 
<<<<<<< HEAD
'''Returns the sum of a and b'''
=======
'''Adds a and b'''
>>>>>>> master
return a+b

在这种合并冲突中,自从上次拉取以来, sum()函数的文档字符串已在本地进行了编辑/添加,并且由协作者(在远程上)进行了更改。

请注意,默认的合并冲突样式不会告诉您上次拉动时出现了什么(这称为共同祖先)。 也就是说,您无法区分合并冲突中的更改是对现有代码的编辑还是新的添加。

如果在命令行中运行此命令,则可以启用三向差异:

 $ git config merge.conflictStyle diff3 

通过此更改,您可以区分已被编辑的行和属于添加的行。

这是三向合并的补充:

 <<<<<<< HEAD 
'''Returns the sum of a and b'''
|||||||
=======
'''Adds a and b'''
>>>>>>> master

这是一种三向合并的编辑:

 <<<<<<< HEAD 
'''Returns the sum of a and b'''
|||||||
'''Retruns the sum of a and b'''
=======
'''Adds a and b'''
>>>>>>> master

不在单个分支机构上进行协作的更多原因

可以想象,处理合并冲突可能会突然中断工作流程,这是不受欢迎的。 有时,某人甚至可能提交更改,从而破坏了您所需的功能或更改了行为,从而创建了无法预期的不受欢迎的新任务来修复。

如果您不明白为什么头痛不只是处理合并提交和冲突的原因,请以这种方式考虑。 共享单个git存储库(不使用分支)就像Google Doc。 当然,除了推和拉(这就是合并发生的原因)之外,Git处于脱机状态,但这是一个基本相似的概念。

如果您使用Google文档与合作伙伴一起撰写论文,则当您的合作伙伴对介绍进行更改时,该更改会立即显示在屏幕上。

使用非分支的Git存储库,如果有人进行了修改module.py的提交,则无论是否愿意,您也将立即(在拉取时)获得那些更改。 例如,如果他们编辑了您大量使用的module.py函数的输入或输出,则可能会出现问题。

现在,您必须先修复使用该功能的每个位置,然后才能执行任何工作(否则您可能会牺牲运行代码的能力)。 如果他们在几周内进行了多次更改,您可以想象它会变得多么令人生气。

一个严重不足的解决方案是仅在完全完成任务后才提交(或仅推送)。 该解决方案失败了,因为它否定了您最初使用托管版本控制所获得的许多好处。

更好的解决方案是使用分支。 您和您的协作者都共享同一个存储库,但是您可以具有并行的修订历史记录。 也就是说,您都可以进行提交而不必被迫立即应用另一方的提交。 当一个任务完全完成并准备好集成到其他分支中时,您可以使用git merge应用更改。

与分支机构合作

创建Git存储库时,默认情况下有一个分支: master 。 在典型的分支存储库工作流中,该分支充当所有其他分支的中心。 当您要将完成的任务交付给团队的其他成员时,您可以将其合并到master分支中,然后他们可以将更新后的master分支全部合并到各自的工作分支中。 也就是说,当您查看活动的Git存储库的master分支(例如Linux内核GitHub)时,每个不是简短错误修复的提交都是合并提交。

建立分支

因此,当您开始一项任务时,您应该做的第一件事就是为其建立一个新分支。 为您的分支选择一个简短的描述性名称。

 $ git branch tables 

该命令不会返回任何内容,但是您刚刚创建了一个名为tables的新分支。 要确认您已这样做,可以运行:

 $ git branch 
* master
tables

这表明您有两个分支:当前正在使用的master和刚刚创建的tables

 $ git checkout tables 
Switched to branch 'tables'

现在您在分支tables 。 您可以像往常一样在此分支上工作,并且在tables分支上所做的任何提交都不会影响master分支。 您已经隔离了所做的更改(同时仍可将其提供给您的协作者使用),并且您可以自由地按自己的意愿进行提交,而不必担心与他人打扰。

推新分支

还有一点需要注意的是,当您要将更改推送到GitHub时,可能会遇到如下错误:

 $ git push 
fatal: The current branch tables has no upstream branch.
To push the current branch and set the remote as upstream, use
  git push --set-upstream origin tables 

运行他们给您的命令可以正常工作,但让我们首先对该消息进行一点解码。 当您尝试推送时,您当前的分支没有配置的远程/上游分支(在这种情况下,这两个术语可以互换)。

因为没有上游配置,所以需要给它一个附加标志,告诉它推送到远程命名origin上的tables分支。 如果不存在(本例中不存在),则在远程上创建具有该名称的分支。

 $ git push --set-upstream origin tables 
Username for 'https://github.com': kilofarad
Password for 'https://kilofarad@github.com':
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: Create a pull request for 'tables' on GitHub by visiting:
remote: https://github.com/kilofarad/omf/pull/new/tables
remote:
To https://github.com/kilofarad/omf.git
* [new branch] tables -> tables
Branch 'tables' set up to track remote branch 'tables' from 'origin'.

从输出中可以看到,该命令已在GitHub的服务器上创建了一个新的(远程)分支,以跟踪您的本地表分支。

分支之间合并

在分支之间合并的两种主要情况对于基本的分支存储库工作流程很重要。

  1. 当我们将变更从母版合并到工作分支中时
  2. 当我们将最终确定的更改从工作分支合并到主分支中时

通过命令行合并

从master合并到我们的工作分支非常简单。 首先,您需要切换到master分支并拉动以确保您具有最新更改。

 $ git checkout master 
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
$ git pull
Already up to date.

然后,切换回您的工作分支(在我的情况下是tables ),然后git merge master 。 超级简单。

 $ git checkout tables 
Switched to branch 'tables'
Your branch is up to date with 'origin/tables'.
$ git merge master
Updating 6e2ccddc..57af6cfb

运行命令后,系统将提示您进行合并提交或警告某些合并冲突。 该过程只是git pull后半部分,它首先在执行git merge之前从GitHub获取所需的远程分支。 因为您已经在本地拥有master分支,所以不再需要前半部分。

通过GitHub合并

当您要将已完成的任务从工作分支合并到master分支时,从技术角度来看,没有理由为什么您无法通过命令行合并并将其推送到服务器上。

但是,当合并到master分支时,允许其他人查看并批准您的更改是一个好主意-确保这些更改中没有任何可能影响其工作的更改。 这就是GitHub的拉取请求的来源。

您可以通过转到https://github.com/repoOwner/repoName/pull/new/branchName来从分支发起拉取请求。

从那里,确保您的基础是master而比较是tables (或您选择的工作分支)。 Github告诉您更改是否会造成任何合并冲突,允许您为合并请求添加标题并添加简短描述,并允许您向协作者请求审阅或将其分配给合并请求。

创建拉取请求后,其他人可以对其进行注释,甚至可以直接添加提交(通过将提交添加到表分支),直到批准并准备将其合并到master分支中为止。 准备好要合并后,只需按“合并”拉取请求按钮即可。

包起来

本指南介绍了与分支机构一起舒适工作所需的基本工作流程。 如果您想了解更高级的Git工作流程,建议阅读有关隐藏,更复杂的分支管理或重新定级的内容。