.NET DevOps 接入指南 | Git flow & GitLab workflow

引言

GitLab作为一站式DevOps平台,其首先最基础的功能必然是源代码版本管理。而其源代码管理是基于Git,Git通过支持分支独立安全地处理功能和错误修复,实现安全、可靠和快速的分布式软件开发工作流。Git作为一个源代码版本管理工具,其允许多种分支策略和工作流程。但很多组织在使用过程中,由于采用了不合理的分支策略导致工作流过于复杂,使得版本管理混乱。为了规范Git流程,业界提出了第一个Git分支提案:Git flow,接下来就先来介绍下Git flow,以便更好的理解Gitlab flow。

Git flow

Git flow作为一种分支策略标准,其分支策略如下图所示,从图中可以看出其主要有六大分支,其流程是:

  1. 首先从main分支创建develop分支用于开发,main分支不允许push,只允许合并

  2. 然后基于develop分支创建feature分支进行特性开发,特性开发完毕后合并到develop分支

  3. 也可基于develop分支创建bugfix分支进行bug修复,bug修复完毕后合并到develop分支

  4. develop分支验证无误后,再从develop分支合并到release分支,同样release分支不允许push,只允许合并

  5. release分支进行预生产环境验证无误后,将release分支合并到main分支,并创建Tag标识版本号

  6. 如果在生产环境发现问题需要热修复,则基于main分支创建hotfix分支,修复验证通过后,直接从hotfix分支合并到main分支,并通过Tag创建新版本号。

  7. 其中mainrelease分支是不允许修改的。

image.png

在实际项目中如何应用Git flow呢?可以通过git flow命令行进行应用,对于Windows系统只要安装git后即可直接使用,其他系统需要自行安装git-flow插件。安装成功后即可在git bash中执行git flow,可以看到包含以下命令:


$ git flow

usage: git flow <subcommand>

Available subcommands are:

  init      Initialize a new git repo with support for the branching model.

  feature  Manage your feature branches.

  bugfix    Manage your bugfix branches.

  release  Manage your release branches.

  hotfix    Manage your hotfix branches.

  support  Manage your support branches.

  version  Shows version information.

  config    Manage your git-flow configuration.

  log      Show log deviating from base branch.

Try 'git flow <subcommand> help' for details.

接下来就在本地创建一个GitFlow.Demo项目,来讲解下git flow的应用流程。

初始化仓库

首先了解下如何使用git flow初始化一个支持分支模型的git仓库,参照以下步骤即可完成:


shengjie@Thinkpad MINGW64 /d/Gitlab/Demos

$ mkdir GitFlow.Demo # 创建项目目录

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos

$ cd GitFlow.Demo/ # 进入目录

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo

$ git flow init # 初始化一个支持分支模型的git代码仓库

Initialized empty Git repository in D:/Gitlab/Demos/GitFlow.Demo/.git/

No branches exist yet. Base branches must be created now.

Branch name for production releases: [master] main  # 命名生产分支,将master更名为main

Branch name for "next release" development: [develop] # 以develop命名开发分支,直接回车即可

How to name your supporting branch prefixes?

Feature branches? [feature/] # 以feature命名特性分支,直接回车

Bugfix branches? [bugfix/] # 以bugfix命名bug修复分支,直接回车

Release branches? [release/] # 以release命名发布分支,直接回车

Hotfix branches? [hotfix/] # 以hotfix命名热修复分支,直接回车

Support branches? [support/] # 以support命名支持分支,直接回车

Version tag prefix? [] # 指定版本标识前缀,直接回车

Hooks and filters directory? [D:/Gitlab/Demos/GitFlow.Demo/.git/hooks]

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop) # 初始化成功后,会自动切换到develop分支

$ git branch # 查看初始化的分支

* develop

  main

$ git flow config # 查看当前git flow 配置

Branch name for production releases: main

Branch name for "next release" development: develop

Feature branch prefix: feature/

Bugfix branch prefix: bugfix/

Release branch prefix: release/

Hotfix branch prefix: hotfix/

Support branch prefix: support/

Version tag prefix:



初始化成功后,将本地代码库映射到远程仓库,直接使用上一节创建的GitFlow.Demo项目作为远程仓库,在项目页找到克隆地址,然后执行git remote add origin [https://gitlab.shengjie.dev/demos/gitflow.demo.git](https://gitlab.shengjie.dev/demos/gitflow.demo.git)(注意,这里要替换为自己的仓库地址)完成远程仓库映射,最后再执行git push -u --all将本地分支推送到远程。

操作feature分支

接下来演示下如何使用feature分支进行特性开发,主要使用git flow feature命令进行操作:


$ git flow feature help # 查看 git flow feature 命令

usage: git flow feature [list] # 查看本地feature 列表

  or: git flow feature start # 开启一个新的feature

  or: git flow feature finish # 完成一个新的feature,会自动删除feature分支,并合并到develop分支

  or: git flow feature publish # 如果需要code review,可以执行该命令将feature分支推送到远程仓库

  or: git flow feature track

  or: git flow feature diff

  or: git flow feature rebase

  or: git flow feature checkout

  or: git flow feature pull

  or: git flow feature delete



shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git flow feature start feature1 # 创建feature1 特性分支

//...

Summary of actions:

- A new branch 'feature/feature1' was created, based on 'develop'

- You are now on branch 'feature/feature1'

Now, start committing on your feature. When done, use:

    git flow feature finish feature1

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (feature/feature1)

$ touch readme.txt # 创建文件

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (feature/feature1)

$ git add .; git commit -m 'Add readme' # 提交文件

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (feature/feature1)

$ git flow feature finish # 完成feature开发

//...

Summary of actions:

- The feature branch 'feature/feature1' was merged into 'develop' # feature1 分支被合并到develop分支

- Feature branch 'feature/feature1' has been locally deleted # feature/feature1 分支已经被删除

- You are now on branch 'develop' # 当前分支切换到develop分支

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git push --set-upstream origin develop # 推送到远程develop分支

操作release分支

如果基于最新develop分支本地环境自测验证无误后,就可以进行提测,主要是将develop分支合并至release分支,触发GitLab CI/CD ,自动构建并发布至测试环境,进行发布主要使用git flow release命令进行操作:


shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git flow release help # 查看git flow release 命令

usage: git flow release [list]

  or: git flow release start # 开启一个新的release

  or: git flow release finish # 完成release

  or: git flow release publish # 发布release至远程仓库,进行

  or: git flow release track

  or: git flow release delete

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git flow release start v1.0 # 创建 v1.0 release发布分支

//...

Summary of actions:

- A new branch 'release/v1.0' was created, based on 'develop'

- You are now on branch 'release/v1.0'

Follow-up actions:

- Bump the version number now!

- Start committing last-minute fixes in preparing your release

- When done, run:  git flow release finish 'v1.0'

创建release分支后,一般会使用git flow release publish命令将其推送到远程仓库,触发GitLab CI/CD流水线,将该release分支发布到测试环境。


shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (release/v1.0)

$ git flow release publish # 推送至远程分支

//...

Summary of actions:

- The remote branch 'release/v1.0' was created or updated

- The local branch 'release/v1.0' was configured to track the remote branch

- You are now on branch 'release/v1.0'

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (release/v1.0)

在测试环境进行验证无误后,才可以使用git flow release finish命令将此次release标记完成,进而合并到main分支,演示如下:


$  git flow release finish v1.0 # 完成v1.0 release

//...

Summary of actions:

- Release branch 'release/v1.0' has been merged into 'main' # 合并release1到main分支

- The release was tagged 'v1.0' # 打标签为v1.0

- Release tag 'v1.0' has been back-merged into 'develop' # 将v1.0合并到develop分支

- Release branch 'release/v1.0' has been locally deleted; it has been remotely deleted from 'origin' # 将release/v1.0 从本地和远程删除

- You are now on branch 'develop' # 切换至develop分支

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git checkout main # 切换到主分支

Switched to branch 'main'

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (main)

$ git push --set-upstream origin main # 推送到远程分支

操作bugfix分支

如果测试人员在release分支对应的测试环境进行验证时发现了一个问题:创建的readme.txt未添加任何描述。开发人员就可以通过bugfix分支解决,主要使用git flow bugfix命令:


$ git flow bugfix help

usage: git flow bugfix [list]

  or: git flow bugfix start # 创建bugfix分支

  or: git flow bugfix finish # 完成bugfix分支

  or: git flow bugfix publish # 如果需要code review, 可以执行该命令将bugfix分支推送到远程仓库

  or: git flow bugfix track

  or: git flow bugfix diff

  or: git flow bugfix rebase

  or: git flow bugfix checkout

  or: git flow bugfix pull

  or: git flow bugfix delete

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (release/v1.0)

$ git flow bugfix start bug1 # 开启bug1分支

//...

Summary of actions:

- A new branch 'bugfix/bug1' was created, based on 'develop' # 可以看出是基于develop分支创建的bug1分支

- You are now on branch 'bugfix/bug1'

Now, start committing on your bugfix. When done, use: git flow bugfix finish bug1



shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (bugfix/bug1)

$ echo 'Hello git flow!' > readme.txt # 修改readme

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (bugfix/bug1)

$ git commit -am 'Update readme' # 提交readme

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (bugfix/bug1)

$ git flow bugfix finish bug1 # 完成bug1修改

//...

Summary of actions:

- The bugfix branch 'bugfix/bug1' was merged into 'develop' # 合并到develop分支

- bugfix branch 'bugfix/bug1' has been locally deleted # 删除bug1 分支

- You are now on branch 'develop' # 切换至develop分支

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git push # 再次推送到远程develop分支

完成问题修复后,可再从develop分支进行发布release

操作hotfix分支

在release分支合并到main分支后,就可以进行生产环境发布了。基于main分支发布到生产环境后,如果发现紧急问题,则可以通过hotfix分支进行热修复。热修复流程注意使用git flow hotfix命令操作,演示如下:


shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git flow hotfix help

usage: git flow hotfix [list]

  or: git flow hotfix start # 启动热修复

  or: git flow hotfix finish # 完成热修复

  or: git flow hotfix publish # 推送热修复至远程分支

  or: git flow hotfix delete

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git flow hotfix start hotfix1

//...

Summary of actions:

- A new branch 'hotfix/hotfix1' was created, based on 'main' # hotfix 分支是基于main分支创建的

- You are now on branch 'hotfix/hotfix1'

Follow-up actions:

- Start committing your hot fixes

- Bump the version number now!

- When done, run:  git flow hotfix finish 'hotfix1'

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (hotfix/hotfix1)

$ sed -i 's/git flow/GitFlow/#' readme.txt # 假设是需要将readme.txt中的git flow 替换为GitFlow

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (hotfix/hotfix1)

$ git commit -am 'Fix hotfix1: update git flow to GitFlow' # 提交更改

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (hotfix/hotfix1)

$ git flow hotfix publish # 推送到远程分支,以便发布验证

//...

Summary of actions:

- The remote branch 'hotfix/hotfix1' was created or updated

- The local branch 'hotfix/hotfix1' was configured to track the remote branch

- You are now on branch 'hotfix/hotfix1'

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (hotfix/hotfix1)

$ git flow hotfix finish # 将此次hotfix标记完成

//...

Summary of actions:

- Hotfix branch 'hotfix/hotfix1' has been merged into 'main' # 合并到main分支

- The hotfix was tagged 'hotfix1' # 打标签

- Hotfix tag 'hotfix1' has been back-merged into 'develop' # 合并到develop分支

- Hotfix branch 'hotfix/hotfix1' has been locally deleted; it has been remotely deleted from 'origin' # 删除本地和远程的hotfix1分支

- You are now on branch 'develop' # 切换到develop分支

shengjie@Thinkpad MINGW64 /d/Gitlab/Demos/GitFlow.Demo (develop)

$ git push -u --all # 推送所有分支至远程仓库

$ git push -u --tags # 推送所有tag至远程仓库

经过上面的实操,相信对git flow 有了一定的认识,通过标准的git flow可以对整个开发过程有更多控制。但相信大家对新的git flow标准引入的多个分支策略感到复杂,在实际项目当中,根据需要按需使用分支即可。比如,仅使用maindevelopfeature分支也是可以的。

GitLab Workflow

GitLab Workflow是在Git Flow的基础之上改进的工作流,一个基本的GitLab 工作流如下图所示。其将代码版本管理与项目和部署管理工具结合起来,使得团队在无缝使用Git的基础上,同时可以进行议题跟踪、请求合并、持续集成和部署。

image.png

从图中可以看出,其流程的起点是创建议题。那什么是议题呢,议题对应的是Issue,对应的是GitLab中的议题模块。为什么将Issue翻译为议题,而不是问题呢?因为该模块不仅仅是管理问题清单,还可为功能需求、任务或者要讨论的想法。GitLab中的议题模块,包含列表、看板、服务台和里程碑三个子功能模块,如下图所示。其中列表用于展示议题列表,看板用于按议题状态分组展示,服务台主要是基于邮件进行议题管理,里程碑可用于项目迭代计划。接下来就来具体看下如何使用议题模块进行项目计划和状态跟踪。

image.png

修改配置

在开始之前,需要设置默认分支受保护分支,设置路径为:设置->仓库。对于刚创建的GitFlow.Demo项目来说,其默认分支为master,因此如果要实施git flow,需要将其更改为develop,如下图所示。其中对于选项:自动关闭默认分支上的引用问题是指当提交的日志中或合并请求的标题/描述中通过包含指定关键字:fix/fixes/fixed/close/closes/closed/resolve/resolves/resolved #1 完成对Issue #1 的引用,则当完成到默认分支的提交或合并,关联的Issue #1会自动关闭。

image.png

对于受保护分支的设置,其目的是限制指定分支只能通过合并请求进行代码合并来确保分支的稳定性。对于Git flow 中的developmain\masterrelease分支而言,都有必要进行分支保护以推行Code Review。

image.png

创建标记

在GitLab中,可以通过Label标记议题和合并请求,进行归类。在项目信息下有个标记子菜单,其允许自行创建或点击生成一组默认的标记按钮自动生成一组默认的标记,默认标记如下图所示,其中最后一个task是自行创建的。

image.png

创建里程碑

GitLab 里程碑可以用来进行项目计划,比如通过里程碑进行迭代开发。创建里程碑时仅需指定标题、开始时间、截止时间和描述即可。下图中,创建了一个名为学会Git flow基本流程的里程碑。

image.png

创建议题

有了里程碑,就可以对里程碑进行拆分,可以拆分出需求、任务等,创建议题的页面如下图所示,主要录入标题、关联里程碑、指派团队成员、标记及截止日期等。

image.png

紧接着就可以通过关联上面的里程碑学会Git flow基本流程task标记创建议题完成对里程碑的拆解,拆解的议题如下图所示:

image.png

创建合并请求

对于合并请求,GitLab提供了配置项,可通过路径为:项目->设置->通用->合并请求,修改合并请求配置,默认配置如下图所示,在实际项目中可以根据需要进行相应修改,比如关闭默认启用'删除源分支'选项,启用流水线必须成功所有讨论都必须解决的合并检查。

image.png

为了方便演示,创建一个新的用户Jeff,并邀请为项目开发者。创建用户步骤为:管理员->用户->新建用户,邀请用户步骤为:项目信息->成员->邀请成员,如下图所示:

image.png

邀请成功后,使用Jeff账号登录GitLab。打开GitLab.Demo项目,然后点击项目右上角的派生(Fork)按钮,创建一个项目的副本到Jeff自己的仓库中,以实现在不影响原始项目的情况进行更改。

image.png

派生(Fork)成功后的项目,将拥有独立的项目配置,Jeff可以按照需要配置自己的默认分支和受保护的分支,这里建议仅修改默认分支develop分支即可。修改后,即可将代码克隆(Clone)到本地并添加对上游仓库(upstream)的引用以进行代码同步,步骤如下:


shengjie@Thinkpad:~/gitlab$ git clone https://gitlab.shengjie.dev/Jeff/gitflow.demo.git #克隆至本地

shengjie@Thinkpad:~/gitlab$ cd gitflow.demo/

shengjie@Thinkpad:~/gitlab/gitflow.demo$ git remote add upstream https://gitlab.shengjie.dev/demos/gitflow.demo.git # 添加对远程源仓库的引用

shengjie@Thinkpad:~/gitlab/gitflow.demo$ git remote -v

origin  https://gitlab.shengjie.dev/Jeff/gitflow.demo.git (fetch)

origin  https://gitlab.shengjie.dev/Jeff/gitflow.demo.git (push)

upstream        https://gitlab.shengjie.dev/demos/gitflow.demo.git (fetch)

upstream        https://gitlab.shengjie.dev/demos/gitflow.demo.git (push)

shengjie@Thinkpad:~/gitlab/gitflow.demo$ git flow init # git flow 初始化

假设Jeff现在需要负责完成上面创建的第2个议题,也就是:#2: 使用git flow feature 进行特性开发。那么其可以通过git flow feature start task2来开展,步骤如下:


shengjie@Thinkpad:~/gitlab/gitflow.demo$ git flow feature start task2 # 创建一个名为task2的feature进行功能特性开发

Switched to a new branch 'feature/task2'

Summary of actions:

- A new branch 'feature/task2' was created, based on 'develop'  # 基于develop分支自动创建 fature/task2 分支

- You are now on branch 'feature/task2'

Now, start committing on your feature. When done, use:

    git flow feature finish task2

shengjie@Thinkpad:~/gitlab/gitflow.demo$ echo 'Use git glow feautre!' >> readme.txt  # 在原有的readme.txt文件上追加一行文字,表示完成task2开发

shengjie@Thinkpad:~/gitlab/gitflow.demo$ cat readme.txt

Hello GitFlow!

Use git glow feautre!

shengjie@Thinkpad:~/gitlab/gitflow.demo$ git commit -am 'fix #2: I have tried git flow feature command' #提交改动

[feature/task2 9b063ac] fix #2: I have tried git flow feature command

1 file changed, 1 insertion(+)

shengjie@Thinkpad:~/gitlab/gitflow.demo$ git flow feature publish # 发布当前feature/task2到个人远程分支

//...

Summary of actions:

- The remote branch 'feature/task2' was created or updated

- The local branch 'feature/task2' was configured to track the remote branch

- You are now on branch 'feature/task2'

将本地feature/task2分支推送到个人远程仓库后,可打开GitLab确认,如下图所示。

image.png

紧接着就可以通过图中的创建合并请求快捷入口为刚刚的提交创建合并请求,或者通过项目首页右侧的合并请求菜单创建合并请求。主要分为以下几步:

  1. 选择源分支和目标分支:这里显然是要从Jeff/gitflow.demo/feature/task2分支合并到上游的demos/gitflow.demo/develop分支,如下图所示:
image.png
  1. 填写合并请求的标题、描述、指定标记和合并人,同时还可以关联里程碑来方便负责合并的同事识别本次更改是否为需要此时合并到本次待发布的分支,另外如果勾选下图中的Delete source branch when merge request is accepted.(当合并请求通过后删除源分支),则当请求完成合并,源分支自动关闭。如下图所示:
image.png
  1. 合并请求。源分支的管理员,会在右上角收到合并请求的消息通知,点击打开,确认变更内容后,即可点击合并按钮进行合并。其中可以勾选删除源分支,则当成功合并后,源分支也就是Jeff:feature/task2会自动删除,同时由于使用了fix #2关键字将合并请求关联到了#2 Issue,因此成功合并后,Issue也会自动关闭。
image.png

创建发布

GitLab 也贴心的提供了在线发布功能,可通过路径:部署->发布->新建发布,进行在线版本发布。通过选择发布的标签,关联里程碑,填写发布说明,后点击创建发布即可,步骤如下图1所示,创建成功后,会看到如下图2的发布详情。
image.png
image.png

以上就是Git flow 结合GitLab的基本流程,下一节就来介绍下GitLab CI/CD,来领略GitLab 工作流的真正威力。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容