Linux下,github/git项目开发基本流程
我们的目的
场景
比如说现在有一个很牛逼的项目,我们进入项目地址,
想将这个项目复制到自己的github仓库,然后你还想将
仓库中的代码拉取到本地进行修改,修改完你还要将本地的
修改后的代码推送到自己的github仓库,更甚至你还想将自己
复制过来并修改后的代码再还给原作者,请求人家让你合并。
明确的分支名
明确可以贡献代码后,fork项目,然后clone到本地,后在master上创建一个新的分支(branch)。好处:
- 确保你的分支语义明确,一看就大概明白你用它来完成什么。
- 后续可以更好的和master同步代码。
例如:
nodes/atom_improvements
scheuduler/dirty_scheuduler_collapse
kernel/clean-history-shell
提交日志(Commit Message)
日志(Commit Message)要尽量避繁就简,这可以让你的PR更容易被人理解和接受。
- 首行总结要尽量少于50字符。
- 附加的更详细的说明,保持宽度在72字符左右。
- 使用“Fix bug"代替”Fixed bug"或“Fixes bug"。
- 多使用列表说明问题。
代码礼仪(Code Standard)
每个人都会有自己的代码风格,到底是用制表符(Tab)还是空格(Space)?每行是80字符还是120字符?这种圣战不应该在PR中出现,PR应该遵循项目已有的风格。例如:如果原来使用的驼峰命名变量,PR中就应该使用驼峰命名。
整理日志(Rebase)
git rebase是一个让你可以改变历史的命令!通过它轻易地重新排列,编辑或合并历史日志。
- 编辑以前提交过的日志。
- 把多条日志合并成一条日志。
- 删除或回滚一些不必要的日志。
例如:有时图个方便,会把代码分阶段性提交,到真正完成时,希望Review的人看到是最终的结果。
git commit -am "Add Account Form"
git commit -am "Add Passwd Form"
git commit -am "Add Verification Code Form"
你需要把上面的都合并成一条提交日志。可以使用rebase功能。
git rebase -i HEAD~3
- -i表示打开交互模式(interactive mode)。
- HEAD~3表示检查最近3条日志。
- 输入的数字过大会导致fatal: Need a single revision错误,可以减小数字。
随后会通过默认的编辑器(一般是vi)打开一个文本:
pick cee46ac Add Verification Code Form
pick 5dd4924 Add Passwd Form
pick 27dc5ce Add Account Form
# Rebase 925891e..cee46ac onto 925891e (3 commands)
#
# 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
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
需要重点关注的是前3行,后面带#的是注释说明,不会出现在日志中。默认是pick选项,就是保持此条日志不变,其它选项可以看上面的注释,我们的目标是把3条合成一条,并修改日志内容。所以可以使用到f(fixup)与r(reword)选项。最终效果如下。
r cee46ac Add Verification Code Form
f 5dd4924 Add Passwd Form
f 27dc5ce Add Account Form
保存后,会直接再弹出一个文本编辑器用于重写日志内容:Add login UI.
关于rebase各种选项的详细说明。
提交变更(Submit PR)
当所有的commit都准备好时,就可以在网页上选择对应的分支创建PR。最后检查一下
- 标题,描述是否简洁清晰?
- 如果改动是可见的,是否需要附上一个截图或gif说明?
- 想PR被合并后自动关闭对应的issue,可以在描述的结尾加上一行Closes #issue编号。
如果PR改动很大,你想边改边得到别人及时的反馈,可以先创建PR后,在标题上加上[WIP]是Work In Progress的缩写,表示工作还未完成。但尽量不要把未完成的PR提交到别人的项目上(可能会引起别人反感),通常WIP的PR都是自己的项目里面使用就行了。
审查/合并(Review/Merge)
PR提交后,维护者会对它进行逐行的审查(review),大家可以共同讨论,看是否有考虑不周或者更好的方案,在这过程中,你可以根据建议随时改进代码,然后push到分支上,PR就会同步改动。当所有的改动都被批准后,PR应该就会被合并啦!
同步上游分支(Upstream)
如何保持fork分支与上游分支(upstream)同步?
先查看一下你目前git状态。
$ git remote -v
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
以上说明: 你的origin分支指向的是你fork的分支。
指定上游地址。
$ git remote add upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git
upstream分支指向上游地址,这里的upstream名字可以任意指定,只是一般都把上游地址都叫upstream。
检查地址是否设置成功。
$ git remote -v
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (fetch)
origin https://github.com/YOUR_USERNAME/YOUR_FORK.git (push)
upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (fetch)
upstream https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY.git (push)
从upstream分支上拉取最新代码。
$ git fetch upstream
remote: Counting objects: 75, done.
remote: Compressing objects: 100% (53/53), done.
remote: Total 62 (delta 27), reused 44 (delta 9)
Unpacking objects: 100% (62/62), done.
From https://github.com/ORIGINAL_OWNER/ORIGINAL_REPOSITORY
* [new branch] master -> upstream/master
切换到自己的master上,然后把upstream分支上更新内容合并到master上。
$ git checkout master
Switched to branch 'master'
$ git merge upstream/master
Updating a422352..5fdff0f
Fast-forward
README | 9 -------
README.md | 7 ++++++
2 files changed, 7 insertions(+), 9 deletions(-)
delete mode 100644 README
create mode 100644 README.md
这时你的本地master就和上游同步成功啦,但是这只是表示你的本地master,一般你还需要把本地master同步到GitHub下的远程分支上。
$ git push origin master
项目协作者视角
首先Fork一个项目,把它变成你自己GitHub下的项目。
成功后可在自己GitHub账户下看到刚才fork过来的项目。将项目用命令行clone到本地。
$ git clone https://github.com/你自己GitHub用户名/project.git
$ cd project
更新代码至本地,与源码保持一致:默认本地为origin,一般远程为upstream
$ git remote add upstream https://github.com/sourcename/project.git
查看本地分支和 远程分支对应名称是否正确:即orgin为本地fork的地址,upstream为远程的项目地址
$ git remote -v
基于master分支进行开发
执行 git clone 命令后我们会默认处于 master 分支下,同时系统会自动将 origin 设置成该远程仓库的标识符。也就是说,当前本地仓库的 master 分支与 GitHub 端远程仓库(origin)的 master 分支在内容上是完全相同的。
拉取远程的master到本地:注意每次提交之前都要先进行拉取,防止代码冲突(防止upstream仓库的实时更新)
$ git pull upstream master
基于master(start point)分支,创建一个开发分支dev,此时的dev分支和master分支一般无二。
$ git checkout -b dev
请注意,此时在dev分支上进行所有的更改,如果不进行一个版本创建的话,即使使用了git add命令将更改添加到暂缓区,而没有下一步git commit进行版本创建,切回master分支,你会发现你在dev分支上做的修改,怎么也在master分支上出现了,所以在某个分支上完成一个阶段的开发一定要创建版本,避免混乱。
若开发一半时,接到通知需要修复master分支上的bug,此时的开发才进行一半,确实没办法进行版本创建时,请参考git stash命令。
在origin仓库创建dev分支。
$ git push origin dev:dev
项目前期准备工作就已经处理好了,接下来就是正常的项目开发了:
// 写代码
$ vim xxx
....写写写写写写写写......
// 每次提交项目之前一定要拉取,防止冲突(基于哪个分支开发,就拉哪个分支)
$ git pull upstream master
$ git push origin dev:dev
// 拉取之后在进行自己代码的提交
$ git add .
$ git commit -m "我的第一个PR实验"
$ git push origin dev:dev
然后在网页上,发起pull request,注意pull request到你基于开发的那个分支,这里是master,否则可能会有冲突。
被合并后马上就能在项目中看到你的名字啦~
基于其他分支(非master)下进行开发
上面说了,执行 git clone 命令后我们会默认处于 master 分支下
我们用 git branch -a 命令查看当前分支的相关信息。添加 -a 参数可以同时显示本地仓库和远程仓库的分支信息。
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/dev
remotes/origin/其他分支名1
remotes/origin/其他分支名2
remotes/origin/其他分支名3
.....
remotes/upstream/dev
remotes/upstream/其他分支名1
remotes/upstream/其他分支名2
remotes/upstream/其他分支名3
remotes/upstream/其他分支名4
.......
这里的origin分支和upstream的分支如果你没有新建分支的话是没有区别的,如果新建分支则origin会存在你新建的分支,而upstream内没有
一般来说,一个优秀的项目会有多个分支,这些分支都具有不同的功能,且正在开发,如果我们需要协作开发其中一个分支,则需要将该分支拉下来,即获取远程分支,例如这里的dev分支。
$ git checkout -b dev origin/dev
Branch dev set up to track remote branch dev from origin.
Switched to a new branch 'dev'
-b 参数的后面是本地仓库中新建分支的名称。为了便于理解,我们仍将其命名为 dev,让它与远程仓库的对应分支保持同名。新建分支名称后面是获取来源的分支名称。
例子中指定了origin/dev,就是说以名为 origin 的仓库(这里指GitHub 端的仓库)的 dev 分支为来源,在本地仓库中创建并切换至dev 分支。
这些工作完成后,就可以按照自己的思路进行在该分支下进行二次开发,在代码写完之后,先在本地创建一个版本,然后push,最后在网页上发起pull request。
仓库管理者视角
当有人通过上述步骤发送PR至你的github仓库时,你会得到这样的界面
如果你对他的提交无任何异议,你可以直接点击Merge pull request进行直接合并。
如果你想调试一下看看请求者所提交的功能的正确性,请点击图片中红框的可点击链接,你会得到以下的提示,
现在我们回到本地linux系统进行操作,
步骤1:
新建并切换至一个新的分支,起点为master分支
//git checkout -b|-B <new_branch> [<start point>]
//如果是-b,则branch-name分支不存在,git会在start-point上创建它,如果branch-name分支已经存在,那么会将操作失败。
//如果是-B,如果它不存在则创建<new_branch>; 否则,它被重置。
$ git checkout -b xCodeleaner-master master
现在新的分支是创建好了,但是它只是本地master分支的一个拷贝,并没有任何区别,所以这个时候就要将提交者的更改从提交者的仓库中拉取下来。
//git pull <远程主机名> <远程分支名>:<本地分支名>
//如果远程分支是与当前分支合并,则冒号后面的部分可以省略:
$ git pull https://github.com/xCodeleaner-master master
此时,如果你觉得他写的有点问题,有些内容需要修改,那你就修改,修改完别忘了创建版本
$ vim xxx
$ git add .
$ git commit -m 'fix bug'
步骤2:
切换至master分支(也可以是别的分支,你想将提交合并进去的分支),然后进行合并
//切换至master分支,并进行合并
$ git checkout master
$ git merge --no-ff xCodeleaner-master
然后会突然跳出一个可怕的界面,不要慌,它只是让你写一下将该分支合并到master分支的必要性,也就是让你解释一下,你为啥要合并这个分支到master,毕竟master分支很重要。默认的解释的Merge branch ‘pull request的请求名’。
如果你没啥可以解释的直接ctrl+x,按提示离开该界面就行。
接着你git log看一眼,
$ git log
最后,再将本地Linux的改变推送到远程github上
$ git push origin master
然后网页上的github直接就同步了,对,就是这么快
参考链接(Reference)
https://zhuanlan.zhihu.com/p/51199833
https://blog.csdn.net/JxiaoZhang/article/details/84820147
请把大鹤真细心打在公屏上!!