1.1 Git
1.2 UI工具: TortoiseGit
推荐理由:可查看 版本分支图|Revision Graph
注:仅支持windows, 其他UI工具: gitk (在git bash中输入gitk即可)、GUI Clients。
Git 是一个开源的分布式版本控制系统。
详见 Git 配置环境及常用命令整理 或 Git使用教程。注:后者类似于手册或教科书。
origin副本fork自 upstream,再将origin副本clone到电脑中为local副本。
以test项目( https://github.com/birdflyi/test.git )为例:
github网站
upsteam(上游的项目): birdflyi/test.git (https://github.com/birdflyi/test.git)
origin(fork后的项目): your/test.git (https://github.com/your/test.git)
注:origin又可以被称为下游项目downstream
电脑端
local(克隆到本地的项目): your/test.git (/path/to/your/git)
┌─ GitHub WebSite ────────────────────────────────────────────┐
│ ┌─ remote ────────────────────────────────────────────────┐ │
│ | ┌─ upstream ──────────┐ ┌─ origin ────────────┐ │ |
│ | │ birdflyi/test.git │──fork──>│ your/test.git │ │ |
│ | └─────────────────────┘ └─────────────────────┘ │ |
│ | | │ |
│ └────────────────────────────────────────────┼────────────┘ │
└──────────────────────────────────────────────┼──────────────┘
clone
┌─ Computer Client ────────────────────────────┼──────────────┐
| v |
| ┌─ local:work-dir ─────┐ |
| │ your/test.git │ |
| └──────────────────────┘ |
└─────────────────────────────────────────────────────────────┘
即初始化时数据流向为: upstream----fork----->origin----clone---->local 然而,本地在clone时只提供了origin的地址,upstream仍未设置,因此需要单独设置一下upstream:
git remote add upstream https://github.com/birdflyi/test.git
接下来需要拉代码、修改并提交、推代码。假定通过1-3节,origin与local之间的操作已经可以顺利完成,那么我们还需要与upstream通信:
协作必然要把自己的代码同步到upstream的,如何同步呢?
——使用PR(即PullRequest)即可。
其中拉代码包含fetch和pull,区别详见 git pull 和 git fetch的区别?
实际的local中包含若干存储区,其中我们能直接查看和修改的仅仅是工作区working directory,其他存储区被隐藏着。
工作区working directory 与 本地仓库local repository 之间存在 暂存区staging ;
本地仓库local repository 与 远程仓库 remote repository 之间存在 远程副本remote copy :
图片来自 git pull 和 git fetch的区别?注解(可跳过):
**工作区(working directory),**简言之就是你工作的区域。对于git而言,就是的本地工作目录。工作区的内容会包含提交到暂存区和版本库(当前提交点)的内容,同时也包含自己的修改内容。
**暂存区(stage area, 又称为索引区index),**是git中一个非常重要的概念。是我们把修改提交版本库前的一个过渡阶段。查看GIT自带帮助手册的时候,通常以index来表示暂存区。在工作目录下有一个.git的目录,里面有个index文件,存储着关于暂存区的内容。git add命令将工作区内容添加到暂存区。
**本地仓库(local repository),**版本控制系统的仓库,存在于本地。当执行git commit命令后,会将暂存区内容提交到仓库之中。在工作区下面有.git的目录,这个目录下的内容不属于工作区,里面便是仓库的数据信息,暂存区相关内容也在其中。
**远程版本库(remote repository),**与本地仓库概念基本一致,不同之处在于一个存在远程,可用于远程协作,一个却是存在于本地。通过push/pull可实现本地与远程的交互;
**远程仓库副本,**可以理解为存在于本地的远程仓库缓存。如需更新,可通过git fetch/pull命令获取远程仓库内容。使用fech获取时,并未合并到本地仓库,此时可使用git merge实现远程仓库副本与本地仓库的合并。
数据流图如下所示:
┌─ GitHub WebSite ───────────────────────────────────────────────────────────────────────────────────────────────────┐
│ ┌─ remote ─────────────────────────────────────────────────────────────────────────────────────────────────────┐ │
│ | ┌─ origin ────────────┐ ┌─ upstream ──────────┐ | │
│ | │ your/test.git │=====PR===>│ birdflyi/test.git │ | |
│ | └─────────────────────┘ └─────────────────────┘ | │
│ | | | ^ | | │
│ └─────────────────────────────────────────────────────────┼───┼───┼────────────────────────────┼───────────────┘ │
└────────────────────────────────────────────────────────────┼───┼───┼────────────────────────────┼──────────────────┘
fetch [origin]| | |push origin fetch|upstream
pull [origin]| | |
┌─ Computer Client ──────────────────────────────────────────┼───┼───┼────────────────────────────┼──────────────────┐
| ┌─ local ─────────────────────────────────────────────────┼───┼───┼────────────────────────────┼───────────────┐ |
| v | | v | |
| | ┌─ remote copy:origin ─┐ | | ┌─ remote copy:upstream ─┐ | |
| | | | | | | | | |
| | | your/ |<-┼---| | your/ | | |
| | | test.git |<-| |<-push-condition-| test.git | | |
| | | | | | behind by | | | |
| | └──────────────────────┘ | | 1 commit └────────────────────────┘ | |
| | merge| | | | |
| | reset --soft HEAD~1| | | | |
| | * v v | | |
| | ┌─ wk-dir ─┐ ┌─ staging ─┐ ┌─ loc-repo ─┐ | |
| | | >>red>> | add . | >>green>> | commit -m | [ahead] | | |
| | | your/ |────────────>| your/ |─────────────────>| your/ | | |
| | | test.git |<────────────| test.git |<─────────────────| test.git | | |
| | |[uptodate]| restore . | <<red<< | reset . | <<green<< | | |
| | └──────────┘checkout -- .└───────────┘restore --staged .└────────────┘ | |
| | | | | | |
| | |---------------------commit -a-------------------------->| | |
| | |<----------------reset --hard HEAD~1---------------------| | |
| | | | | | |
| └──────────────────────────────────────────────────────────────────────────────────────────────────────────────┘ |
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
其中PR操作发生在远端而非本地。remote copy:upstream是不能自动获得远端的协作结果(如其他人的PR结果)的,然而push的前提是remote copy:upstream要落后于loc-repo一个版本,因此要在push之前执行fetch upstream,有冲突时还需要先解决冲突才能推送。
*仅有工作区wk-dir的状态可以在本地直接查看和修改。
注意:git pull 有额外的将remote copy:upstream同步到remote copy:origin的作用,从而实现origin副本通过fast-forward与upstream保持同步。推荐养成在git fetch upstream后即git pull的好习惯。
从upstream到本地的remote copy:upstream,完整形式为git fetch upstream [<远程分支名>]:
git fetch upstream
从origin到本地的remote copy:origin,并merge到loc-repo,相当于fetch+merge,通常省略orgin,完整形式为git pull origin [<远程分支名>:<本地分支名>]:
git pull
!从loc-repo可直接重置代码wk-dir,此命令慎用,从图中可以看出可以直接影响工作区,需要提前备份工作区的修改,完整形式为git reset --hard HEAD 或 git reset --hard HEAD~0,~n代表重置为当前版本之前的第n个版本,0表示重置为当前版本,放弃新添加的更改:
git reset --hard
从loc-repo可直接重置代码wk-dir,此命令不会丢失当前工作区修改,若不想备份,建议使用git reset命令,之后再解决冲突,完整形式为git reset HEAD 或 git reset HEAD~0。
git reset
将<extra-branch>
合并到当前的分支<base-branch>
中,需要提前使用git checkout <base-branch>
切换好分支,运行完成后当前的分支是主分支:
git merge <extra-branch>
注:若当前的分支<base-branch>
落后于<extra-branch>
,使用此命令则会直接将当前的分支HEAD移动到<extra-branch>
的HEAD位置,称为fast-forward
模式,若不想立即移动到最新的位置,可以加--no-ff
禁用fast-forward模式。
将当前的分支<current-branch>
变基到<base-branch>
末尾,需要提前使用git checkout <base-branch>
切换好分支,运行完成后将是<base-branch>
+<current-branch>
的单向链表,当前分支的基改变,即删除最近一次分叉处的父节点,重新链接到<base-branch>
的尾部,此方式能保障历史回溯性,除了合入主分支和release外,均推荐使用此方式合并分支:
git rebase <base-branch>
注:也可以使用git rebase <base-branch> <post-branch>
或者git rebase --onto <base-branch> <post-branch-start> <post-branch-end>
直接rebase,而不必配合当前分支, 注意这种方式的参数都是按结果的HEAD指向顺序放置的。详见[Git] Git整理(四) git rebase 的使用。
从本地的loc-repo推送到origin的远端分支<remote-branch>
上,通常是loc-repo处于ahead状态,且需要比remote copy:origin及remote copy:upstream领先1个commit:
git push -f origin <remote-branch>
注:执行此语句之前一般需要执行git fetch upstream
,并解决协作者与自己的冲突,协作者提交的结果仅能在remote copy:upstream中获取,故此语句常常是解决推送失败的关键。
参考分支管理策略:
在实际开发中,我们应该按照几个基本原则进行分支管理:
首先,
master
分支应该是非常稳定的,仅用来发布新版本;开发都在
dev
分支上,也就是说,dev
分支是不稳定的,到某个时候,比如1.0版本发布时,再把dev
分支合并到master
上,在master
分支发布1.0版本;每个人承担的任务不同,都应该有自己的分支
feature
,完成后向dev
分支上合并。
如图:
对应到github默认的分支管理策略:
master <--> main
dev <--> develop
feature <--> feature
参考开源贡献指南
能换位思考
相互尊重,相互包容
拿来的东西要有出处哦,尊重劳动成果也是必要的
讲文明,懂礼貌
批评中肯,就事论事
好奇心很重要,同理心也很重要
保护自己的隐私,保护他人的隐私
或者:行为准则
欢迎提issue、提PR(PullRequest)、增加功能、修改bug、更新文档、美化界面等。意见建议、相关信息、互助、文档和项目的改进并重。
如果您是初次贡献,可以先从 good first issue
列表中认领一个比较小的任务来快速参与社区贡献。您可以直接在相应 issue 中回复参与意愿,然后参照下面的 GitHub 工作流指引解决 issue 并按照规范提交 PR,通过 review 后就会被 merge 到 main分支。
如果您想要贡献代码,您可以参考 5.4 工作流程,提交对应的 PR。如果您的 PR 包含非常大的变更,比如模块的重构或者添加新的组件,请先提出相关 issue,发起详细讨论,达成一致后再进行变更,并为其编写详细的文档来阐述其设计、解决的问题和用途。注意一个 PR 尽量不要过于大。如果的确需要有大的变更,可以将其按功能拆分成多个单独的 PR。
-
将仓库 fork 到自己的 GitHub 下
注:通常还生成ssh的key,后面提交文档的时候会用到。需要到生成的路径中找到key,复制文件内容,设置到git账户的setting中。详见 Git 配置环境及常用命令整理 。
-
将 fork 后的仓库 clone 到本地,设置你的upstream。
git clone https://github.com/YOUR-USERNAME/query_clickhouse.git cd query_clickhouse git remote add upstream https://github.com/birdflyi/query_clickhouse.git
可以通过
git remote -v
查看设置,应显示origin
和upstream
的fetch和push设置。 -
保持origin及本地分支与upstream远程相应分支一致(通过
fetch upstream
和rebase
操作)切换到develop分支
git checkout develop
保持origin及本地分支与upstream远程相应分支一致:
git fetch upstream develop git pull git rebase upstream/develop
注意:git pull 有额外的将upstream同步到origin的作用,从而实现origin副本通过fast-forward与upstream保持同步。推荐养成在git fetch upstream后即git pull的好习惯。
如果rebase发生冲突,需要解决冲突:即输入
git fetch upstream
,git pull
,git rebase upstream/develop
之后,手动修改冲突文件,再用git add .
和git rebase --continue
完成此阶段。1.-3.已完成准备工作,当一个PR完成后,可以跳过1.-2.的步骤,从3.开始准备。
4.-7.将完成提交和推送工作。
-
在develop分支上再创建新的分支,在新的分支上进行开发操作(请确保对应的变更都有测试用例或 demo 进行验证)
git checkout develop git checkout -b YOUR-NEW-BRANCH
-
在本地修改代码或文件后,提交变更(commit log要能体现主要做了什么)
git add . git commit -m "your commit message."
-
保持origin及本地分支与upstream远程相应分支一致(通过
fetch upstream
和rebase
操作)[与3.相同]git fetch upstream develop git pull git rebase upstream/develop
注意:git pull 有额外的将upstream同步到origin的作用,从而实现origin副本通过fast-forward与upstream保持同步。推荐养成在git fetch upstream后即git pull的好习惯。
如果rebase发生冲突,需要解决冲突:即输入
git fetch upstream
,git pull
,git rebase upstream/develop
之后,手动修改冲突文件,再用git add .
和git rebase --continue
完成此阶段。 -
将提交 push 到 fork 的仓库下
git push -f origin YOUR-NEW-BRANCH
注:完整命令为:
git push -f origin YOUR-NEW-BRANCH:YOUR-NEW-BRANCH
-
创建一个 pull request (PR)
在您的远程仓库网页中提PR。当push完成后,您的项目主页会自动显示出一个 Pull Request 的按钮。若有延迟,可点击分支旁的
New pull request
按钮。如图所示:(这里:YOUR-NEW-BRANCH指origin的develop-lzh分支,提交PR到upstream的develop分支)
提交 PR 的时候请参考 PR 模板。在进行较大的变更的时候请确保 PR 有一个对应的 Issue。
等待reviewer的响应结果。
若PR未被合入,则继续循环4.-7.即可,此步骤中的PR追踪的是upstream和origin的动态差异信息,只需要提交到origin新的修改即可,而不需要关闭未被合入状态的PR再重新开启新的PR。
-
PR被upstream合并后,维护origin
删除开发分支YOUR-NEW-BRANCH,保持origin及本地分支与upstream远程相应分支一致(通过
fetch upstream
和rebase
操作)[与3.相同] a.删除origin开发分支YOUR-NEW-BRANCHgit push origin --delete YOUR-NEW-BRANCH
b.删除本地开发分支YOUR-NEW-BRANCH
git checkout develop -f git branch -D YOUR-NEW-BRANCH
c.保持origin及本地分支与upstream远程相应分支一致(通过
fetch upstream
和rebase
操作)[与3.相同]git fetch upstream develop git pull --ff upstream develop git rebase upstream/develop
注意:git pull 有额外的将upstream同步到origin的作用,从而实现origin副本通过fast-forward与upstream保持同步。推荐养成在git fetch upstream后即git pull的好习惯。
如果rebase发生冲突,需要解决冲突:即输入
git fetch upstream
,git pull
,git rebase upstream/develop
之后,手动修改冲突文件,再用git add .
和git rebase --continue
完成此阶段。下一次PR可以从3.开始准备。
若您发现任何的安全漏洞(或潜在的安全问题),请第一时间通过 [email protected] 邮箱私下联系我们。
所有的代码都需要经过 committer 进行 review。以下是我们推荐的一些原则:
- 可读性:代码遵循我们的开发规约,重要代码需要有详细注释和文档
- 优雅性:代码简练、复用度高,有着完善的设计
如果您有任何问题与建议,请通过邮箱 [email protected]联系我们。