【Python程序开发系列】5000字总结:Git-Fork模式下软件开发的工作流程和常用命令

这是Python程序开发系列原创文章,我的第194篇原创文章。

一、背景

         直接克隆项目和先fork后克隆项目都是使用 Git 进行代码协作的常见方式,它们在不同的场景下有不同的用途和好处。

        先fork后克隆项目是指先将原始仓库复制到自己的 GitHub 帐户下(称为 fork),然后再从自己的 fork 仓库中克隆代码到本地。这种贡献代码方式适用于以下场景:

  • 推送的权限:贡献代码的人没有直接push到中央仓库的权限
  • 项目的复杂度:流程比较多,迭代比较多
  • 参与的人数:人数太多,每个人建一个中央仓库的分支是不现实的

【Python程序开发系列】5000字总结:Git-Fork模式下软件开发的工作流程和常用命令_第1张图片

fork模式下,自己的远端(fork的)、中央仓库(被fork的)、本地仓库三者要保持同步(紫色线条的循环)

实际开发过程建议在本地和远程创建一个临时分支进行开发,有以下好处:

  • 隔离开发环境:通过新建分支,你可以将你的工作与主分支隔离开来,确保你的修改不会直接影响主分支的稳定性。这样,如果出现问题或需要进行其他工作,你可以轻松切换回主分支,而不会受到你的修改的影响。

  • 并行开发:通过新建分支,多个开发人员可以同时在不同的分支上进行工作,而不会相互干扰。每个人可以在自己的分支上进行独立的开发和实验,然后通过合并分支的方式将工作集成到主分支中。

  • 版本控制:新建分支可以帮助你更好地管理代码的版本控制。你可以为每个功能或修复创建一个新的分支,在分支上进行开发和测试,然后在完成后将其合并到主分支中。这样,你可以更轻松地跟踪每个功能或修复的修改历史,并在需要时进行回滚或切换到特定版本。

二、工作流程

2.1 fork

        一般由项目组长建立代码的主仓库(中央仓库),剩余小组开发人员首先要对中央仓库进行fork,就是从中央仓库将项目复制一份到自己的远端仓库(可以复制主分支,也可以选择复制全部分支),这个只需操作一次,之后再进行clone处理。(不要每次看见仓库就直接clone)

2.2 clone

        将项目组长建立的中央仓库Fork之后,将自己的远端仓库clone到本地,git clone 命令默认会克隆远程仓库的所有分支,但只会自动切换到 master 分支。如果你希望克隆指定的分支并自动切换到该分支,可以使用 -b 选项。我们一般都在dev分支上进行开发,所以fork之后一般选择dev分支以ssh的方式进行克隆。

使用ssh协议与远程仓库通信(包括clone、pull、push等操作),需要在远程仓库配置ssh公钥

1、ssh-keygen -t rsa -C xxx@xxxx
2、将~/.ssh/id_rsa.pub或C:\Users\Administrator\.ssh\id_rsa.pub复制

配置之后,本地仓库和远程仓库可以以SSH协议进行克隆、拉取和推送操作:

git clone  []
git clone -b  

之后,可以查看、设置提交的账户邮箱和昵称

查看当前 Git 的邮箱和昵称:
    - git config user.email
    - git config user.name
设置当前 Git 的邮箱和昵称:
    - git config --global user.name "nickname"
    - git config --global user.email "email"

2.3 关联远程仓库、配置连接协议

输入git remote -v查看本地仓库关联的远程情况

git remote -v

项目刚拉下来的时候一般只有两个远程仓库的地址,一个用来fetch,一个用来push,并且这两个都是自己的远程仓库origin,接下来我们需要将本地仓库与中央仓库建立关联,方便以后push和pull进行同步:

git remote add  
# 例子git remote add upstream  

注意:是远程仓库的名称,可以自己取名字;有两种地址形式对应两种协议,一种是https一种是ssh:

配置ssh协议连接(好处是不需要每次输入密码)
    - git remote add origin [email protected]:xxx/xxx.git(添加ssh协议)
删除当前远程仓库使用的这种协议连接
    - git remote rm origin
配置https协议连接
    - git remote add origin https://github.com/xxx/xxx.git(添加https协议)

成功将中央仓库关联到本地仓库之后可以直接push和pull代码。(切记在这种工作模式下,不要直接push中央仓库,一般来说你也没有权限,记着push自己的仓库origin)

2.4 新建本地功能分支并关联远程分支

从这一步到2.6PR是一个开发周期,为了开发一个功能需求。

先查看本地和远程(包括中央仓库和自己远端)有哪些分支:

git branch
git branch -r
git branch -a

新建一个本地功能分支并切换到了该分支:

git checkout -b feat

在自己远端创建一个同名分支,并且本地分支关联:

git push --set-upstream origin feat

将本地的功能分支feat与中央仓库的dev分支进行关联:​​​​​​​

git branch --set-upstream-to=upstream/dev feat
# git branch --set-upstream-to=origin/remote_branch  your_branch
# 其中,origin/remote_branch是你本地分支对应的远程分支;your_branch是你当前的本地分支。

查看本地分支与远程分支关联情况:

git branch -vv

在git clone的时候,本地分支默认与远程主机的同名分支关联,分支建立关联的好处在于git pull和push的时候可以自动识别,建立一种追踪关系。

2.5 开发:pull & stash & pull & add & commit & push

接下来你就可以在这个功能分支进行功能开发。这一步是我们每天重复的工作。

开始一天的工作前,先不要一股脑的在feat分支上直接开敲,先打开git bash ,先pull一下中央仓库保证代码最新:​​​​​​​

git pull upstream
# 由于建立了feat分支(本地功能分支)与upstream/dev关联,可以直接git pull upstream

开敲......

当你这一天结束了,想要提交代码了,这个时候你要明白一件事,你们是合作开发,中央仓库的更新速度是要比你的快的,也就是说很多情况中央仓库的代码都是要比你的新,所以你要先pull 中央仓库的代码。但是直接pull代码可能会直接带来冲突,所以在此之前你需要提交或者将代码放入暂存区stash

git stash save "save message"

将代码放入暂存区之后,直接pull 主仓库的代码:​​​​​​​

git pull upstream
# 由于建立了feat分支(本地功能分支)与upstream/dev关联,可以直接git pull upstream

这样是不会产生冲突的,这时我们将暂存区的内容拿出来(暂存区是一个栈,后放入的内容排在前面):​​​​​​​

git stash list   #查看stash了哪些存储
git stash show   #显示做了哪些改动
git stash apply  #将某个暂存取出,git stash apply stash@{$num}
git stash drop stash@{$num}  #丢弃stash@{$num}存储,从列表中删除这个存储
git stash clear #删除所有缓存的stash
git stash pop ( 这一句的作用相当于 git stash apply stash@{0} + git stash drop stash@{0})。

查看代码变更情况:

git diff #可以查看这次修改了什么,那些妥当,那些不妥当,按q可以退出

提交到暂存区:

git add .  #这里的点是全部修改内容,或者自行选中单个文件

查看提交状态,显示有变更的文件:

git status

提交到本地仓库:

git commit -m "feat:add UserManagement"

提交(包括commit/merge等)规范:

- Title(type:subject)
    - feat:新增功能
    - fix:bug 修复
    - docs:文档更新
    - style:不影响程序逻辑的代码修改(修改空白字符,格式缩进,补全缺失的分号等,没有改变代码逻辑)
    - refactor:重构代码(既没有新增功能,也没有修复 bug)
    - perf:性能, 体验优化
    - test:新增测试用例或是更新现有测试
    - build:主要目的是修改项目构建系统(例如 glup,webpack,rollup 的配置等)的提交
    - ci:主要目的是修改项目继续集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
    - chore:不属于以上类型的其他类,比如构建流程, 依赖管理
    - revert:回滚某个更早之前的提交

feat(user): add user login verify
fix(iaas): fix unstable when create vm server
test(unittest): add unittest
docs(readme): add user guide docs
style(admin): format code of admin module
refactor(app): refactor interactive way in app
chore(ci): add ci pipline

# 完整例子:
- feat(user): add user login verify
- Description:
  - 为用户添加了登录功能,使用了 OAuth 2.0 协议进行验证。
  - Closes #123
    - Closes #问题编号:使用这个格式可以在合并 MR 时关闭单个问题。
  - Closes #123, #124
    - Closes #问题编号, Closes #另一个问题编号:使用逗号分隔多个问题编号,可以在合并 MR 时关闭多个问题。

将本地的分支推送(同步)到自己的远端分支:​​​​​​​

git push origin
# 由于建立了feat分支(本地功能分支)与origin/feat关联,可以直接git push origin

这时如果出现冲突,需要手动解决冲突。

2.6 创建PR,请求合并

        当你觉得这个功能开发完成了,这个周期可以结束了。你就可以进行这一步了,创建PR或MR。这里的PR是自己远端的feat分支-->中央仓库的dev分支

PR合并的方式

  • - merge(合并所有提交):这是最常见的合并方式,它会将源分支(通常是一个 PR 分支)的更改合并到目标分支(通常是主分支)中,并创建一个新的合并提交。这种方式会保留所有提交历史,并且可以轻松地撤销合并。但是,由于它会创建新的提交,因此会使提交历史变得复杂。
  • - squash(扁平化分支合并):这种方式会将源分支的所有提交压缩成一个提交,并将其合并到目标分支中。这种方式会使提交历史变得更加简洁,但是会丢失源分支中的提交历史。此外,由于它会创建新的提交,因此也会使提交历史变得复杂。
  • - rebase(变基并合并):这种方式会将源分支的提交移动到目标分支的末尾,并创建一个新的合并提交。这种方式可以保留所有提交历史,并且可以使提交历史保持线性,但是需要注意的是,它会改变源分支中的提交历史,并且可能会导致冲突。
  • - 当一个 PR 被合并时,它所包含的提交会被合并到目标分支中,而不是源分支中。也就是说,合并后的提交包含在目标分支中,而不是源分支中。如果您想查找合并后的提交的 SHA 值,您应该查询目标分支,而不是源分支。

        一般一个功能分支对应一个PR,提交PR后,不要立马删除该分支,不应继续向自己远端的feat分支提交代码,而是等待管理员合并,并且有新的任务写新的代码之前要在本地创建新的功能分支feat1,因为分支合并请求提交之后需要时间,如果合并请求不通过还要在该分支上进行修改。在分支合并请求通过后,可以直接删除功能分支,将最新的代码同步到本地的dev分支并推到自己远端的dev分支,使得本地的dev分支、自己远端的dev分支与中央仓库dev保持同步。

        对于有测试环节的项目来说,分支合并请求通过后,需要基于中央仓库dev分支拉出来一个发布分支,比如叫 release-1.1,中央仓库此刻应该有三个分支,main、dev、release-1.1。在第二迭代周期期间,测试发现bug后,开发就不能在本地feat1上改bug了,而是应该从release-1.1分支拉出来一个子分支,比如release-1.1-redrose2100,然后在本地release-1.1-redrose2100分支改bug,改完bug后,提PR从release-1.1-redrose2100合入到release-1.1分支,同时将改bug期间的commit 通过 git cherry-pick 命令合并到dev分支。这样就做到了发布分支只改bug,dev分支持续开发新功能,同时改的bug还能合入到新功能中

        如果仓库只有一个主分支master没有dev分支,则默认直接在master分支做开发,上述流程的dev直接改为master即可。

三、小结

        当你有pull、push、fetch、merge这几个同步操作时,就有可能提示冲突,冲突产生的根本原因在于在本地和远端(包括自己远端和中央仓库)同步出错,修改了同一个文件的同一行代码,git不知道应该保留哪个分支的修改内容。比如多人在各自的本地仓库中编辑了同一个文件,然后先提交的人将代码git到服务器之后,后面其它人在另一个地方也修改了该文件。此时,后面的人再git push自己修改过的本地代码到服务器时,或者git pull服务器上别人修改过的代码到本地进行合并时都会提示冲突,无法合并。

        一套规范的流程终极目标是为了更好的协作,避免或减少冲突,提高工作的效率。如果流程不规范,就很容易产生冲突,会在解决冲突问题上浪费太多时间。

作者简介:

读研期间发表6篇SCI数据挖掘相关论文,现在某研究院从事数据算法相关科研工作,结合自身科研实践经历不定期分享关于Python、机器学习、深度学习、人工智能系列基础知识与应用案例。致力于只做原创,以最简单的方式理解和学习,关注我一起交流成长。

你可能感兴趣的:(开发技能,python,git,开发语言)