“Social Coding Pull Requests What to Do When Things Get Complicated”可直译为“社交编码中的拉取请求:遇到复杂情况时该怎么做”。以下是对其相关概念及内容的详细解析:
- Social Coding(社交编码):是一种基于互联网的协作式软件开发模式,开发者们通过类似社交媒体的方式进行代码共享、协作和交流。常见的平台如GitHub,开发者可以在上面浏览他人代码、提出问题、提交代码修改建议等,促进了开源项目的发展和开发者之间的合作。
- Pull Requests(拉取请求,简称PR):是社交编码中一个关键功能。当开发者想为某个开源项目贡献代码时,先将项目Fork(复刻)到自己的账户下,在本地进行代码修改后,将修改推送到自己的远程Fork仓库,然后通过提交Pull Request向项目维护者请求将自己的修改合并到主代码库中。提交时需指定合并的源分支和目标分支,并附上修改说明,方便维护者和其他开发者审核。
- What to Do When Things Get Complicated(遇到复杂情况时该怎么做):在提交Pull Request过程中,可能会出现多种复杂情况。例如,在开发者Fork项目后到提交Pull Request期间,主代码库可能发生了变化,这会导致合并时出现冲突;或者开发者想为不同特性或错误修复提交多个Pull Request,需要将它们分开处理等。针对这些情况,可采取以下措施:
- 保持主分支同步:可将主项目设为本地工作副本的远程“origin”,将自己的Fork仓库设为“fork”,通过
git pull origin master等命令及时从主仓库获取最新内容,使本地master分支与主项目保持同步,减少合并冲突。 - 重写分支历史:若主代码库有更新,可使用
git rebase命令将自己的分支重新设置到远程仓库的最新更改上。若重写过程中出现冲突,需先修复冲突再继续。这样可使自己分支的提交历史基于最新的主分支,让拉取请求更易合并。若已将分支推送到Fork仓库,重写历史后需使用git push --force强制推送,但要注意若有其他人基于该分支进行开发,需提前协调,避免其仓库与共享仓库不同步。 - 压缩提交:如果开发者在本地分多个步骤提交了更改,想保留这些小提交,同时又希望将拉取请求作为单个提交呈现给远程仓库,可以使用
git merge --squash命令创建一个新分支,将多个提交压缩为一个,使补丁更易阅读,也便于合并。 - 处理被拒的拉取请求:若拉取请求被拒绝,项目所有者要求进行一些更改,开发者可切换回相关分支,根据要求进行修改,然后使用
git rebase --onto等命令将更改移到拉取请求分支,重新提交拉取请求。
“Social Coding”通常指的是开源社区中的协作式编程,而“Pull Requests”(PR)是GitHub等代码托管平台上用于提交代码变更请求的一种机制。当Pull Requests变得复杂时,需要采取一些策略来应对。以下是对这个主题的详细解析:
- 保持主分支同步:可将主项目设为本地工作副本的远程“origin”,将自己的Fork仓库设为“fork”,通过
1. 理解Pull Requests的复杂性来源
- 代码冲突:当多人同时对同一代码文件进行修改时,可能会出现冲突,导致PR无法顺利合并。
- 代码质量:提交的代码可能不符合项目的编码规范、测试覆盖率不足或存在潜在的漏洞。
- 功能范围:PR可能涉及的功能范围过大,难以快速审查和理解。
- 沟通问题:开发人员与维护者之间可能存在理解上的偏差,导致需求不明确或解决方案不符合预期。
- 依赖关系:PR可能依赖于其他未完成的功能或修复,增加了合并的复杂性。
2. 应对复杂Pull Requests的策略
- 代码冲突的解决
- 及时沟通:当发现冲突时,及时与相关开发者沟通,了解冲突的原因。
- 手动解决:通过工具(如Git)手动解决冲突,确保代码的正确性。
- 重新同步:在解决冲突后,重新同步分支,确保所有更改都已正确合并。
- 提高代码质量
- 代码审查:通过代码审查(Code Review)确保代码符合项目规范,包括编码风格、注释、测试等。
- 自动化测试:运行自动化测试(如单元测试、集成测试)确保代码变更不会引入新的问题。
- 持续集成(CI):利用CI工具(如GitHub Actions、Jenkins)自动运行测试和构建,及时发现潜在问题。
- 优化功能范围
- 拆分PR:如果PR范围过大,可以将其拆分为多个小的PR,每个PR专注于一个具体的功能或修复。
- 清晰描述:在PR描述中详细说明变更的目的、范围和实现方式,便于审查者快速理解。
- 加强沟通
- 明确需求:在开发前与维护者或项目负责人明确需求,避免因理解偏差导致的返工。
- 定期更新:在PR过程中,定期更新状态,及时反馈问题和进展。
- 处理依赖关系
- 明确依赖:在PR描述中明确指出依赖的其他PR或功能,确保维护者了解上下文。
- 协调合并顺序:与维护者协商PR的合并顺序,确保依赖关系得到妥善处理。
3. 工具和流程的支持
- 使用分支管理工具:如Git Flow或GitHub Flow,通过规范的分支管理减少冲突和混乱。
- 利用代码托管平台功能:GitHub等平台提供了丰富的功能,如代码审查评论、CI集成、自动合并等,充分利用这些功能可以提高效率。
- 建立项目规范:制定清晰的代码规范、提交规范和审查流程,确保团队成员遵循一致的标准。
4. 总结
当Pull Requests变得复杂时,关键在于及时沟通、优化代码质量和合理管理功能范围。通过使用合适的工具和流程,可以有效降低复杂性,提高开源协作的效率和质量。
以下是提取整理的图片文本:
某网课教育平台欲添加在线作业批改系统,以实现高效的作业提交与批改,并进行统计。学生和讲师的基本信息已经初始化为数据库中的学生表和讲师表。系统的主要功能如下:
(1)提交作业。验证学生标识后,学生将电子作业通过在线的方式提交,并进行存储。系统给学生发送提交成功的通知,通知中包含唯一编号;并通知讲师有作业提交。
(2)下载未批改作业。验证讲师标识后,讲师从系统中下载学生提交的作业。下载的作业将显示在屏幕上。
(3)批改作业。讲师按格式为每个题目进行批改打分,并进行整体评价。
(4)上传批改后的作业。将批改后的作业(包括分数和评价)返回给系统,进行存储。
(5)记录分数和评价。将批改后的作业的分数和评价记录在学生信息中,并通知学生作业已批改。
(6)获取已批改作业。根据学生标识,给学生查看批改后的作业,包括提交的作业、分数和评价。
(7)作业抽检。根据教务人员标识和批改后的作业样本,给出抽检意见,然后形成抽检报告给讲师。
现采用结构化方法对在线作业批改系统进行分析与设计,获得如图1-1所示的上下文数据流图和图1-2所示的0层数据流图。
【问题1】(3分)使用说明中的词语,给出图1-1中的实体E1~E3的名称。
【问题2】(2分)使用说明中的词语,给出图1-2中的数据存储D1~D4的名称。
【问题3】(8分)根据说明和图中术语,补充图1-2中缺失的数据流及其起点和终点。
【问题4】(2分)若发送给学生和讲师的通知是通过第三方Email系统进行的,则需要对图1-1和图1-2进行哪些修改?用100字以内文字加以说明。
【问题1】
- E1:学生
- E2:讲师
- E3:教务人员
【问题2】
- D1:学生表
- D2:讲师表
- D3:作业存储(存放学生提交作业)
- D4:学生作业分数和评价记录(记录批改后作业分数和评价 )
【问题3】
从图中可知,数据流“Email”起点为系统,终点为学生和讲师。补充缺失数据流:学生提交作业后,系统给讲师发送“有作业提交”通知的数据流;讲师批改作业后,系统给学生发送“作业已批改”通知的数据流 。
【问题4】
修改方式:在图1 - 1中,添加从“系统”到“学生”和“讲师”的数据流,标注为“发送Email通知”;在图1 - 2中,在对应提交作业、批改作业后的处理环节,添加向学生、讲师发送Email通知的输出数据流,体现通知功能。
根据您提供的文本内容,图1-1中的实体E1、E2、E3分别代表以下内容:
- E1:学生(Student)
- E2:讲师(Instructor)
- E3:教务人员(Administrative Staff)
这些实体代表了系统中的主要用户角色,他们与系统交互以完成作业提交、批改、存储和通知等操作。
根据您提供的文本描述,学生提交作业的过程如下:
-
登录系统:学生首先需要登录到网课教育平台的在线作业批改系统。
-
验证学生标识:系统会验证学生的标识(可能是学号、用户名或邮箱等),以确认学生的身份。
-
上传作业:学生将电子作业通过在线的方式提交。这可能涉及到选择文件、拖放文件到指定区域或使用上传按钮来提交作业。
-
提交确认:提交作业后,系统会进行存储,并给学生发送提交成功的通知。通知中会包含一个唯一编号,用于追踪作业的提交状态。
-
通知讲师:系统同时会通知讲师有新的作业提交,以便讲师可以下载并批改作业。
这个过程确保了作业的提交是安全和可追踪的,同时也让讲师能够及时了解作业提交的情况。
以下是确保系统发送的Email通知准确无误到达学生和讲师的方法:
数据准确性方面
- 初始信息校验:在学生和讲师信息初始化录入时,设置邮箱格式校验机制,利用正则表达式等方式检查邮箱地址是否符合规范,如包含@符号且格式正确等,避免录入无效邮箱。
- 定期信息更新:系统设置提醒功能,定期(如每学期或每年)提示学生和讲师核实并更新个人邮箱信息,确保其为常用且有效的邮箱。
发送过程管理方面
- 使用可靠邮件服务:选择像SendGrid、Mailgun等专业且可靠的邮件发送服务提供商,这类服务商有较高的邮件送达率和完善的技术支持,能处理复杂网络环境下的邮件发送问题。
- 发送状态监控:系统集成邮件发送状态跟踪功能,可实时获取邮件的发送状态,如是否成功投递、是否被接收服务器拒绝等。一旦发现发送失败,及时记录错误信息并尝试重新发送,同时向管理员预警。
- 设置退信处理机制:针对因邮箱地址不存在、邮箱已满等原因导致的退信情况,系统自动将退信信息归类分析,对于可修正的问题(如邮箱已满提示)通知用户处理,对于无效邮箱地址通知用户更新。
技术优化方面
- IP信誉维护:若系统自行搭建邮件服务器发送邮件,要注重维护IP信誉,避免因发送垃圾邮件等行为导致IP被列入黑名单。可通过规范邮件发送行为、与反垃圾邮件组织合作等方式保持良好IP信誉。
- 邮件内容合规:严格规范Email通知的内容格式和主题,避免使用敏感词汇、大量特殊字符或诱导性表述,防止邮件被接收方服务器误判为垃圾邮件而拦截。
- 采用SSL/TLS加密:在邮件发送过程中启用SSL(Secure Sockets Layer)或TLS(Transport Layer Security)加密协议,保障邮件在传输过程中的安全性和完整性,降低被拦截或篡改的风险。
- 根据您提供的文本描述,并没有明确指出作业提交后多久能收到反馈的具体时间。这通常取决于几个因素:
-
讲师的批改速度:讲师批改作业的速度会影响学生收到反馈的时间。如果讲师能够迅速批改作业,学生就能更快地收到反馈。
-
作业的复杂性:作业的难度和所需批改的时间也会影响反馈的及时性。复杂的作业可能需要讲师花费更多时间来批改。
-
作业提交的时间:如果学生在讲师的工作时间之外提交作业,可能需要等到讲师的下一个工作日才能开始批改。
-
系统的通知机制:系统设计的通知机制也会影响反馈的及时性。如果系统能够即时通知讲师新作业的提交,并且讲师能够及时响应,那么反馈的时间可能会更短。
-
作业的数量:如果讲师需要批改大量的作业,那么单个作业的批改时间可能会被推迟。
在实际操作中,教育平台可能会设定一些标准操作流程来确保学生能够在合理的时间内收到作业反馈。例如,可能会规定讲师在收到作业后的一定时间内完成批改并返回反馈。如果需要更具体的信息,可能需要查看该网课教育平台的具体规定或与讲师沟通。
Scenario: you want to contribute some code to an open source project hosted on a public git repository service like github. Lots of people make pull requests to projects I’m involved in and many times they are more complicated to merge than they need to be, which slows down the process a bit. The basic workflow is conceptually simple:
fork a public open source project
make some changes to it locally and push them up to your own remote fork
ask the project lead to merge your changes with the main codebase
and there is an excellent account of this basic workflow in a blog by Keith Donald.
Complications arise when the main codebase changes in between the time you fork it and the time you send the pull request, or (worse) you want to send multiple pull requests for different features or bugfixes, and need to keep them separate so the project owner can deal with them individually. This tutorial aims to help you navigate the complications using git.
The descriptions here use github domain language (“pull request”, “fork”, “merge” etc.), but the same principles apply to other public git services. We assume for the purposes of this tutorial that the public project is accepting pull requests on its master branch. Most Spring projects work that way, but some other public projects don’t. You can substitute the word “master” below with the correct branch name and the same examples should all be roughly correct.
To help you follow what’s going on locally, the shell commands below beginning with “$” can be extracted into a script and run in the order they appear. The endpoint should be a local repository in a directory called “work” that has an origin linked to its master branch (simulating the remote public project) and two branches on a private fork. The two branches have the same contents at their heads, but different commit histories (as per the ASCII diagram at the bottom).
The Two Remote Repositories
If you are going to send a pull request, there are two remote repositories in the mix: the main public project, and the fork where you push your changes.
It’s a matter of taste to some extent, but what I like to do is make the main project the remote “origin” of my working copy, and use my fork as a second remote called “fork”. This makes it easy to keep track of what’s happening in the main project because all I have to do is
git fetch origin
and all the changes are available locally. It also means that I never get confused when I do my natural git workflow
git checkout master
git pull --rebase
… build, test, install etc …
which always brings me up to date with the main project. I can keep my fork in sync with the main project simply by doing this after a pull from master:
git push fork
Initial Set Up
Let’s create a simple “remote” repo to work with in a sandbox. Instead of using a git service provider we’ll just do it locally in your filesystem (using UN*X commands as an example).
$ rm -rf repo fork work
$ git init repo
$ (cd repo; echo foo > foo; git add .; git commit -m “initial”; git checkout git rev-parse HEAD)
(The last checkout there was to leave the repository in a detached head state, so we can later push to it from a clone.) From now on, pretend “repo” is a public github project (e.g. git://github.com/SpringSource/repo.git).
The “fork” URL in this clone command would be something like git@github.com/myuserid/repo.git. Now we’ll create the fork. This is equivalent to what github does when you ask it to fork a repository:
$ git clone repo fork
$ (cd fork; git checkout git rev-parse HEAD)
Finally we need to set up a working directory where we make our changes (remember “repo” = git://github.com/SpringSource/repo.git):
$ git clone repo work
$ cd work
$ git checkout origin/master
Because we cloned the main public repo that is by default the remote “origin”. We are going to add a new remote so we can push our changes:
$ git remote add fork …/fork
$ git fetch fork
$ git push fork
The local repository now has a single commit and looks something like this in gitk (or your favourite git visiualization tool):
A (origin/master, fork/master, master)
In this diagram, “A” is the commit label, and in brackets we list the branches associated with the commit.
Get the Latest Stuff
You can always get the latest stuff from the main repo using
git checkout master
git pull --rebase
and sync it with the fork
git push fork
If you operate this way, keeping master synchronized between the main repo and your fork as much as possible, and never making any local changes to the master branch, you will never have any confusion about where the rest of the world is. Also, if you are going to send multiple pull requests to the same public project, they will not overlap each other if you keep them separate on their own branches (i.e. not on master).
The Pull Request
When you want to start work on a pull request, start from a master branch fully up to date as above, and make a new local branch
$ git checkout -b mynewstuff
Make changes, test etc:
$ echo bar > bar
$ echo myfoo > foo
$ git add .
$ git commit -m “Added bar, edited foo”
and push it up to your fork repository with the new branch name (not master)
$ git push fork mynewstuff
If nothing has changed in the origin, you can send a pull request from there.
What if the Origin Changes?
For the purpose of this tutorial we simulate a change in the origin like this:
$ cd …/repo
$ git checkout master
$ echo spam > spam; git add .; git commit -m “add spam”
$ git checkout git rev-parse HEAD
$ cd …/work
Now we’re ready to react to the change. First we’ll bring our local master up to date
$ git checkout master
$ git pull
$ git push fork
The local repository now looks like this:
A – B (mynewstuff, fork/mynewstuff)
– D (master, fork/master, origin/master)
Notice how your new stuff does not have origin/master as a direct ancestor (it’s on another branch). This makes it awkward for the project owner to merge your changes. You can make it easier by doing some of the work yourself locally, and pushing it up to your fork before sending the pull request.
Re-writing History on your Branch
If you aren’t collaborating with anyone on your branch it should be absolutely fine to rebase onto the latest changes from the remote repo and force a push:
git checkout mynewstuff
git rebase master
The rebase might fail if you have made changes that are incompatible with somehting that happened in the remote repo. You will want to fix the conflicts and commit them before moving on. This makes life difficult for you, but easy for the remote project owner because the pull requiest is guaranteed to merge successfully.
While you are re-writing history, maybe you want to squash some commits together to make the patch easier to read, e.g.
git rebase -i HEAD~2
…
In any case (even if the rebase went smoothly) if you have already pushed to your fork you will need to force the next push because it has re-written history (assuming the remote repo has changed).
git push --force fork mynewstuff
The local repository now looks like this (the B commit isn’t actually identical to the previous version, but the difference isn’t important here):
A – D (master, fork/master, origin/master) – B (mynewstuff, fork/mynewstuff)
Your new branch has a direct ancestor which is origin/master so everyone is happy. Then you are ready to go into github UI and send a pull request for your branch against repo:master.
What if I want to Keep my Local Commits?
If you committed your changes locally in multiple steps, maybe you want to keep all you little bitty commits, and still present your pull request as a single commit to the remore repo. That’s OK, you can create a new branch for that and send the pull request from there. This is also a good thing to do if you are collaborating with someone on your feature branch and don’t want to force the push.
First we’ll push the new stuff to the fork repo so that our collaborators can see it (this is unnecessary if you want to keep the changes local):
$ git checkout mynewstuff
$ git push fork
then we’ll create a new branch for the squashed pull request:
$ git checkout master
$ git checkout -b mypullrequest
$ git merge --squash mynewstuff
$ git commit -m “comment for pull request”
$ git push fork mypullrequest
Here’s the local repository:
A – B (mynewstuff, fork/mynewstuff)
– D (master, fork/master, origin/master) – E (mypullrequest, fork/mypullrequest)
You are good to go with this and your new branch has a direct ancestor which is origin/master so it will be trivial to merge.
If you weren’t collaborating on the mynewstuff branch, you could even throw it away at this point. I often do that to keep my fork clean:
git branch -D mynewstuff
git push fork :mynewstuff
Here’s the local repo, fully synchronized with both of its remotes:
A – D (master, fork/master, origin/master) – E (mypullrequest, fork/mypullrequest)
Continue Working on your New Stuff
Let’s say your pull request is rejected and the project owner wants you to make some changes, or the new stuff turns into something more interesting and you need to do some more work on it.
If you didn’t delete it above, you can continue to work on your granular branch…
$ git checkout mynewstuff
$ echo yetmore > foo; git commit -am “yet more”
$ git push fork
and then move the changes over to the pull request branch when you are ready
$ git rebase --onto mypullrequest master mynewstuff
All the changes we want are in place now, but the branches are on the wrong commits. As you can see below, mynewstuff is where I want mypullrequest to be, and the remote fork/mynewstuff doesn’t have a corresponding local branch:
A – B – C (fork/mynewstuff)
– D (master, fork/master, origin/master) – E (mypullrequest, fork/mypullrequest) – F (mynewstuff)
We can use git reset to switch the two branches to where we want them (you can probably do this is a graphical UI if you like):
$ git checkout mypullrequest
$ git reset --hard mynewstuff
$ git checkout mynewstuff
$ git reset --hard fork/mynewstuff
and the new repository looks like this:
A – B – C (mynewstuff, fork/mynewstuff)
– D (master, fork/master, origin/master) – E (fork/mypullrequest) – F (mypullrequest)
If we are OK with the pull request being 2 commits, we can just push it as it is:
$ git checkout mypullrequest
$ git push fork
The endpoint looks like this:
A – B – C(mynewstuff, fork/mynewstuff)
– D (master, fork/master, origin/master) – E – F (mypullrequest, fork/mypullrequest)
Or we could rebase it to squash the commits together and force the push, scematically:
git rebase -i HEAD~2
…
git push --force fork
Because origin/master is a direct ancestor of fork/mypullrequest I know that my pull request will be trivial to merge.
Wrap Up
Hopefully this tutorial has given you enough git ammunition to go ahead and make some changes to your favourite open source project and be confident that the merge will be easy. Remember there is always more than one way to do it, and git is a powerful, low-level tool, so your mileage my vary and you might find variants of the approach above preferable or even necessary, depending on your changes.
场景:您希望为托管在公共git存储库服务(如github)上的开源项目贡献一些代码。很多人向我参与的项目发出拉取请求,而且很多时候它们合并起来比需要的复杂,这会稍微减慢进程。基本工作流在概念上很简单:
派生公共开源项目
在本地对其进行一些更改并将其推送到您自己的远程分叉
请项目负责人将您的更改与主代码库合并
Keith Donald在博客中对这个基本的工作流程有一个很好的描述。
当主代码库在分叉和发送拉取请求之间发生变化,或者(更糟的是)您希望为不同的功能或错误修复发送多个拉取请求,并且需要将它们分开,以便项目所有者可以单独处理它们时,就会出现复杂情况。本教程旨在帮助您使用git解决复杂问题。
这里的描述使用github域语言(“pull-request”、“fork”、“merge”等),但同样的原则也适用于其他公共git服务。在本教程中,我们假设公共项目在其主分支上接受pull请求。大多数Spring项目都是这样工作的,但其他一些公共项目则不是这样,您可以用正确的分支名称替换下面的“master”一词,相同的示例都应该大致正确。
为了帮助您了解本地发生的情况,可以将下面以“$”开头的shell命令提取到脚本中,并按它们出现的顺序运行。端点应该是名为“work”的目录中的本地存储库,其中一个源链接到其主分支(模拟远程公共项目)和一个私有分支上的两个分支。这两个分支的头部内容相同,但提交历史不同(根据底部的ASCII图)。

本文详细介绍了如何通过GitHub向开源项目贡献代码,包括派生项目、本地修改、创建拉取请求及解决冲突的过程,帮助开发者顺利参与开源社区。
4585






