个人技术学习

取是能力,舍是境界


  • 首页

  • 关于

  • 排行榜

  • 标签

  • 分类

  • 归档

  • 读书

  • 电影

  • 搜索

理解 Git 分支管理最佳实践

置顶 | 发表于 2017-06-24 更新于 2017-06-30 分类于 Git Hot: ℃
本文字数: 2k 阅读时长 ≈ 2 分钟

Git 分支有哪些

在进行分支管理讲解之前,我们先来对分支进行一个简单的分类,并明确每一类分支的用途。

分支分类

根据生命周期区分

  • 主分支:master,develop;
  • 临时分支:feature/*,release/*,hotfix/*;

根据用途区分

  • 发布/预发布分支:master,release/*;
  • 开发分支:develop;
  • 功能分支:feature/*;
  • 热修复分支:hotfix/*;

分支的用途

  • master:作为发布分支,随时可以将分支上的代码部署到生产环境上。如果在生产环境上发现问题,则以 master 为基准创建 hotfix/* 分支来修复问题;
  • develop:作为开发分支,所有最新的功能都将在该分支下进行开发,develop 也将是所有分支中功能最全,代码最新的一个分支;
  • feature/*:命名规则feature/功能名称,作为新功能的开发分支,该分支从 develop 创建,开发完毕之后需要重新合并到 develop;
  • release/*:命名规则release/v+发布的版本号,作为预发布分支,release/* 只能从 develop 创建,且在 git flow 中同一个时间点,只能存在一个预发布分支。只有当上一个版本发布成功之后删除该分支,之后才能进行下一个版本的发布。如果在预发布过程中发现了问题,只能在 release/* 分支上进行修改;
  • hotfix/*:命名规则hotfix/v+bug修复的版本号,作为热修复分支,只能从 master 分支分离出来。主要是用来修复在生产环境上发现的 bug,修复完成并测试通过后需要将该分支合并回 develop 及 master 上,并删除该分支;

Git 分支管理流程

在上一部分,我们已经明确了每个主分支及辅助分支的用途与来源了,下面我们就来详细了解一下 Git 分支管理的整个流程。
先来看一下分支在完整的功能开发中是如何演变的:
Git branch manage diagram

从上图我们可以看出,我们同时开始了两个功能的开发/研究任务,下面我将以此为基础来讲解分支管理的流程。

  1. 先拉取最新的 develop 分支,然后以最新的 develop 为基准创建两个新的功能分支 feature/f1 和 feature/f2;

    1
    2
    git pull origin develop
    git checkout -b feature/f1 develop
  2. 开发人员在各自的功能分支上进行开发工作,等当前功能分支开发完之后,将当前分支交由测试人员进行测试,测试过程中的问题修复及功能修改均在当前功能分支上进行;

  3. 当 feature/f1 上的开发及测试任务均完成之后,将 feature/f1 合并回 develop ,并删除 feature/f1 ;

    1
    2
    3
    git checkout develop
    git merge --no-ff feature/f1
    git branch -d feature/f1
  4. 从 develop 分支创建新的预发布分支 release/0.2,并部署到预发布环境上测试。在预发布过程中发现问题则直接在 release/0.2 上进行修复;

    1
    git checkout -b release/0.2 develop
  5. 在生产环境中发现一个 bug,从 master 上分离出一个热修复分支 hotfix/bug1,并在上面进行修复、测试并在预发布环境中验证,当都验证通过之后将分支重新合并回 develop 及 master,并在 master 上打一个热修复 tag v0.1.1,最后删除 hotfix/bug1;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    git checkout -b hotfix/bug1 master
    ....................
    ....修复bug..ing....
    ....................
    git checkout develop
    git merge --no-ff hotfix/bug1
    git checkout master
    git merge --no-ff hotfix/bug1
    git tag v0.1.1
    git branch -d hotfix/bug1
  6. 在 feature/f2 分支上的功能 f2 已经开发并测试完成,然后将 feature/f2 合并回 develop,并删除 feature/f2,此时已经存在新功能 f1 的预发布分支 release/0.2,所以需要等待其发布完成之后才能创建预发布分支 release/0.3;

    1
    2
    3
    git checkout develop
    git merge --no-ff feature/f2
    git branch -d feature/f2
  7. 预发布分支 release/0.2 在预发布环境中完全测试通过,随时可以部署到生产环境。但在部署到生产环境之前,需要将分支合并回 develop 及 master,并在 release/0.2 上打一个正式发布版本的 tag v0.2,最后删除 release/0.2;

    1
    2
    3
    4
    5
    6
    git checkout develop
    git merge --no-ff release/0.2
    git checkout master
    git merge --no-ff release/0.2
    git tag v0.2
    git branch -d release/0.2
  8. 当前已经不存在 release/* 预发布分支,所以可以开始功能 f2 的预发布上线。创建预发布分支 release/0.3,并部署预发布环境测试;

    1
    git checkout -b release/0.3 develop
  9. 分支 release/0.3 测试通过,将 release/0.3 合并回 develop 及 master,然后在 master 上打一个正式发布版本的 tag v0.3,最后删除 release/0.3;

Git Flow

上述过程中未使用到 git flow,均是以约定的规范流程进行,大家可以尝试使用 git flow 来管理分支。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#初始化 git flow
# 设置 feature、release、hotfix、tag 的前缀名
git flow init

#开始一个新功能 f1 的开发,以 develop 为基准创建 feature/f1
git flow feature start f1

#....................
#....f1 功能开发中....
#....................

#新功能 f1 开发完成
# 合并回 develop
# 删除 feature/f1 分支
git flow feature finish f1

#开始新功能 f1 的预发布验证,版本定为 0.2
git flow release start 0.2

#新功能 f1 预发布验证通过
# 合并到 master 分支
# 在 release 上打 tag v0.2
# 将 tag v0.2 合并到 develop 分支
# 删除 release/0.2 分支
git flow release finish 0.2

#开始 bug1 的修复,以 master 为基准创建 hotfix/bug1
git flow hotfix start 0.2.1

# bug1 修复完成
# 合并到 master 分支
# 在 hotfix 上打 tag v0.2.1
# 将 tag v0.2.1 合并到 develop 分支
# 删除 hotfix/0.2.1 分支
git flow hotfix finish 0.2.1

至此,Git 分支管理的整个流程已经讲解完,有兴趣的可以看一下具体的分支管理演示 https://github.com/alienwow/gitbranchmanage。
如果有上述讲解中任何不正确的地方,欢迎大家批评指正,如有疑问欢迎一起讨论。

参考文章

Vincent DriessenA successful Git branching model
Joe Guo介绍一个成功的 Git 分支模型

canvas绘制远程图片跨域的问题

发表于 2022-04-22 分类于 前端 Hot: ℃
本文字数: 1.1k 阅读时长 ≈ 1 分钟

一、背景

近期公司需要做一个分享功能,让用户可以保存当前 canvas 生成的图片到本地。同事在实现保存图片到本地的时候出现了如下异常 DOMException: Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported. 并因此遇到了一系列问题,现在记录下来作为参考。

二、解决 Tainted canvases may not be exported

2.1 是什么问题?

搜索了一下该关键词就能出来解决方案

这里面提到了,出现这个问题的原因是当前域名与 canvas 中所绘制的远程图片地址不是同一个域名,触发了 CORS 安全策略,所以出现了跨域问题。canvas 画布中只要存在一个图片存在跨域问题就会导致整个画布数据无法导出。类似的接口如 toBlob()、toDataURL()等。

2.2 如何解决?

在 image 变量上添加以下属性即可 img.crossOrigin = 'anonymous'。但同时引发出了另一个问题:Access to image at 'https://img.xxx.cn/images/abc.png' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.。

三、解决 image 添加 crossorigin=’anonymous’ 后的图片跨域问题 的问题?

3.1 为什么添加 crossorigin=’anonymous’ 后会出现跨域问题呢?

因为同一个 URL 地址在多个地方同时被使用到,而预加载的图片或者常规的 img 标签默认没有添加 crossorigin='anonymous',所以请求服务器后缓存到浏览器本地的资源缓存也不包含跨域信息。此时在 canvas 中使用 URL 图片,同时增加了跨域的设置,那么获取到的数据也不包含跨域信息,则导致与 canvas 中设置的跨域不符则出现了跨域问题

3.2 解决方案?

  1. 是为所有为同一个 URL 地址的图片都添加 crossorigin='anonymous' 或者都不添加;
  2. 是不需要跨域的图片不添加 crossorigin='anonymous',只在需要必须要添加的地方添加 crossorigin,
    同时在图片 URL 后添加时间戳 t=Date.now()。

java.net.SocketException: Too many open files如何解决

发表于 2021-05-12 分类于 Java Hot: ℃
本文字数: 819 阅读时长 ≈ 1 分钟

近日,下班走后接收到业务反馈的一个错误,微信服务器向公众号推送消息或事件后,得到的回应不合法 次数: 5分钟 2731次。

看到是微信推送消息相关,然后看了眼时间,大概定位到了是定时通过微信公众号通知学生上课提醒的业务,所以立马通知开发去排查消息发送日志确定是什么问题。

但是开发查完消息发送日志,并没有发现相关线索,就去查看应用日志,最终才发现了大量如下的异常信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
java.net.SocketException: Too many open files
at java.net.Socket.createImpl(Socket.java:478)
at java.net.Socket.getImpl(Socket.java:538)
at java.net.Socket.setSoTimeout(Socket.java:1159)
at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:120)
at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:376)
at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:393)
at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:186)
at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:89)
at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
at org.apache.http.impl.client.InternalHttpClient.doExecute$original$0fedXLMr(InternalHttpClient.java:185)
at org.apache.http.impl.client.InternalHttpClient.doExecute$original$0fedXLMr$accessor$OtDgrqj0(InternalHttpClient.java)
at org.apache.http.impl.client.InternalHttpClient$auxiliary$OiYkCIMu.call(Unknown Source)
at org.apache.skywalking.apm.agent.core.plugin.interceptor.enhance.InstMethodsInter.intercept(InstMethodsInter.java:86)
at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:83)
at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:108)
at cn.xxxxxxxx.notice.manager.component.impl.WXPushServiceImpl.doAction(WXPushServiceImpl.java:89)
at cn.xxxxxxxx.notice.manager.component.impl.WXPushServiceImpl.globalPush(WXPushServiceImpl.java:57)
at cn.xxxxxxxx.notice.service.component.WXSend.sendAndAck(WXSend.java:159)
at cn.xxxxxxxx.notice.service.component.WXSend.saveRecordAndSend(WXSend.java:139)
at cn.xxxxxxxx.notice.service.component.WXSend.doSend(WXSend.java:90)
at cn.xxxxxxxx.notice.service.component.AbstractSendFactory.lambda$send$0(AbstractSendFactory.java:132)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)

第一反应就是文件打开数超过 Linux 的限制了,莫非还是默认的 1024?。立即执行 ulimit -n 查看当前系统的文件打开符限制,得到的结果是 65535。

看到数字想起来早期已经统一设置了该参数了。继续查看上面的异常信息,发现了几个关键的地方

  1. java.net.SocketException

  2. org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:120)

由此大概率判断可能是网络资源没有得到释放导致?

所以立即执行了 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 命令,显示存在 40多万 个状态为 CLOSE_WAIT 的连接

然后执行 ll /proc/[PID]/fd |wc -l 查看当前应用进程是否有大量状态为 CLOSE_WAIT 的连接,继续应证了该想法。

接下来就比较明确了,进行 Code Review,查看 at cn.xxxxxxxx.notice.manager.component.impl.WXPushServiceImpl.doAction(WXPushServiceImpl.java:89) 相关区域的代码

找到了使用 HttpClient 的地方,确认了当时的开发未释放 httpclient 实例。

参考文章

Spoock/proc/$pid/fd是什么

无法在 docker 中使用 libgdiplus

发表于 2019-09-08 更新于 2017-09-08 分类于 .NetCore Hot: ℃
本文字数: 646 阅读时长 ≈ 1 分钟

概述

近期 @sheng-jie 为 WTM 框架提了个 issue #50 The captcha doesn’t show if deploy the app to the docker,并给出了解决方案及建议。

在此先感谢一下 @sheng-jie的贡献。

解决方案

默认镜像

这个问题主要是在于默认的 docker 镜像 mcr.microsoft.com/dotnet/core/aspnet:2.2 不包含 libgdiplus 的依赖。

在容器运行之后,调用了相关的 API 就将触发以下异常:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.TypeInitializationException: The type initializer for 'Gdip' threw an exception. ---> System.DllNotFoundException: Unable to load DLL 'libgdiplus': The specified module could not be found.
at System.Runtime.InteropServices.FunctionWrapper`1.get_Delegate()
at System.Drawing.SafeNativeMethods.Gdip.GdiplusStartup(IntPtr& token, StartupInput& input, StartupOutput& output)
at System.Drawing.SafeNativeMethods.Gdip..cctor()
--- End of inner exception stack trace ---
at System.Drawing.SafeNativeMethods.Gdip.GdipCreateBitmapFromScan0(Int32 width, Int32 height, Int32 stride, Int32 format, HandleRef scan0, IntPtr& bitmap)
at System.Drawing.Bitmap..ctor(Int32 width, Int32 height, PixelFormat format)
at WalkingTec.Mvvm.Mvc._FrameworkController.GetVerifyCode() in /app/src/WalkingTec.Mvvm.Mvc/_FrameworkController.cs:line 775
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

根据 @sheng-jie 提供的解决方案,只需在 Dockerfile 中添加如下配置命令即可解决。

1
2
3
# install libgdiplus for System.Drawing
RUN apt-get update && \
apt-get install -y --allow-unauthenticated libgdiplus libc6-dev

完整 Dockerfile 文件如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
WORKDIR /app

COPY . .
RUN dotnet publish "./demo/WalkingTec.Mvvm.Demo/WalkingTec.Mvvm.Demo.csproj" -c Release -o /app/out

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# install libgdiplus for System.Drawing
RUN apt-get update && \
apt-get install -y --allow-unauthenticated libgdiplus libc6-dev

ENV ASPNETCORE_URLS http://+:80
ENV ASPNETCORE_ENVIRONMENT Production
ENTRYPOINT ["dotnet", "WalkingTec.Mvvm.Demo.dll"]

alpine 镜像

但是这并未解决 mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine 镜像的问题。

当然解决思路类似,在 alpine 包源上查找 libgdiplus 依赖即可。

注意:当前 alpine 下的 libgdiplus 并未正式发布,还是测试版本

下面我直接给出完整的 Dockerfile 文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
WORKDIR /app

COPY . .
RUN dotnet publish "./demo/WalkingTec.Mvvm.Demo/WalkingTec.Mvvm.Demo.csproj" -c Release -o /app/out

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# install libgdiplus for System.Drawing
RUN apk add libgdiplus --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted

ENV ASPNETCORE_URLS http://+:80
ENV ASPNETCORE_ENVIRONMENT Production
ENTRYPOINT ["dotnet", "WalkingTec.Mvvm.Demo.dll"]

当我以为已经解决 libgdiplus 的问题时,经测试又出现如下问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
fail: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
An unhandled exception has occurred while executing the request.
System.ArgumentException: Font '?' cannot be found.
at System.Drawing.FontFamily.GetGdipGenericSansSerif()
at System.Drawing.FontFamily.get_GenericSansSerif()
at System.Drawing.Font.CreateFont(String familyName, Single emSize, FontStyle style, GraphicsUnit unit, Byte charSet, Boolean isVertical)
at WalkingTec.Mvvm.Mvc._FrameworkController.GetVerifyCode() in /app/src/WalkingTec.Mvvm.Mvc/_FrameworkController.cs:line 795
at lambda_method(Closure , Object , Object[] )
at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)
at Microsoft.AspNetCore.Mvc.Internal.ActionMethodExecutor.SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeActionMethodAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeNextActionFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.InvokeInnerFilterAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeNextResourceFilter()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Rethrow(ResourceExecutedContext context)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeFilterPipelineAsync()
at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.InvokeAsync()
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Routing.EndpointRoutingMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Session.SessionMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)

提示也很明确未找到字体库文件,所以解决思路是需要为 alpine 镜像安装一个字体库。

下面我直接给出完整的 Dockerfile 文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
FROM mcr.microsoft.com/dotnet/core/sdk:2.2-alpine AS build
WORKDIR /app

COPY . .
RUN dotnet publish "./demo/WalkingTec.Mvvm.Demo/WalkingTec.Mvvm.Demo.csproj" -c Release -o /app/out


FROM mcr.microsoft.com/dotnet/core/aspnet:2.2-alpine AS runtime
WORKDIR /app
COPY --from=build /app/out ./

# install libgdiplus for System.Drawing
RUN apk add libgdiplus --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/edge/testing/ --allow-untrusted && \
apk add terminus-font

ENV ASPNETCORE_URLS http://+:80
ENV ASPNETCORE_ENVIRONMENT Production
ENTRYPOINT ["dotnet", "WalkingTec.Mvvm.Demo.dll"]

参考文章

tgogoscreate-custom-docker-alpine-image
alpinelinuxlibgdiplus package
alpinelinuxFonts in alpine

Error Project file is incomplete. Expected imports are missing. 的解决方案

发表于 2018-10-25 分类于 ViaualStudio Hot: ℃
本文字数: 171 阅读时长 ≈ 1 分钟

刚刚打开一个 .net core 的项目,Visual Studio 一直提示我无法打开项目,重新加载也无济于事。错误提示如下所示

1
E:\xxx\Git\xxx\src\xxx\xxx.csproj : error  : Project file is incomplete. Expected imports are missing.

检查了一遍所有的解决方案文件之后才发现我在 global.json 文件中添加了如下设置

1
2
3
4
5
{
"sdk": {
"version": "2.1.301"
}
}

在此错误发生之前,我清理了一下安装的 SDK,其中使用的 v2.1.301 正在被我卸载了。

所以将此配置删除或者修改成本地存在的 SDK 版本即可。

部署生产环境shell脚本

发表于 2018-10-19 分类于 Linux Hot: ℃
本文字数: 60 阅读时长 ≈ 1 分钟

之前写了个发布生产及测试环境的shell脚本,前端的同事一不小心就发布到线上去了,现在特地给他写了个发布线上带确认脚本。

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
echo -e "\033[41;36m Make sure to deploy to the production environment. ? Type 'y' to deploy, type 'n' to quit ...\033[0m"
read reply
if [[ $reply != 'y' ]]; then
echo -e "\033[41;36m quit ...\033[0m"
else
echo -e "\033[41;36m Ready to deploy to production ...\033[0m"

## 在这里添加你要发布到生产环境的 shell 脚本

echo -e "\033[41;36m Deployment to production completion...\033[0m"
fi

Mongodb 常用命令

发表于 2018-01-06 更新于 2018-09-20 分类于 NoSQL Hot: ℃
本文字数: 924 阅读时长 ≈ 1 分钟

基本操作

连接数据库

1
./mongo 127.0.0.1:7003/admin -u admin -p

认证

1
db.auth('userName','pwd')

数据库操作

1
2
# 查看数据库
show dbs

用户管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 查看用户
show users

# 创建用户
use admin
db.createUser(
{
user: "root",
pwd: "abcd-1234",
roles: [ { role: "root", db: "admin" } ]
}
)

# 删除用户
use dbName
db.dropUser("userName")

# 修改密码
# 方法1:
db.changeUserPassword("userName","newPwd")
# 方法2:
db.updateUser("userName",{pwd:"newPwd"})

# 修改权限
db.updateUser("userName",{roles:[{role:"read",db:"testDB"}]})
# 注:updateuser 它是完全替换之前的值,如果要新增或添加 roles 而不是代替它

# 添加权限
db.grantRolesToUser("userName", [{role:"readWrite", db:"testDB"},{role:"read", db:"testDB"}])

# 删除权限
db.revokeRolesFromUser("userName",[{role:"read", db:"testDB"}])

权限详解

内建角色

  1. 数据库用户角色: read、readWrite
  2. 数据库管理角色: dbAdmin、dbOwner、userAdmin
  3. 集群管理角色: clusterAdmin、clusterManager、clusterMonitor、hostManager
  4. 备份恢复角色: backup、restore
  5. 所有数据库角色: readAnyDatabase、readWriteAnyDatabase、userAdminAnyDatabase、dbAdminAnyDatabase
  6. 超级用户角色: root;这里还有几个角色间接或直接提供了系统超级用户的访问(dbOwner 、userAdmin、userAdminAnyDatabase)
  7. 内部角色: __system

角色说明

  1. Read: 允许用户读取指定数据库
  2. readWrite: 允许用户读写指定数据库
  3. dbAdmin: 允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
  4. userAdmin: 允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
  5. dbOwner: 允许在当前DB中执行任意操作
  6. readAnyDatabase: 赋予用户所有数据库的读权限,只在admin数据库中可用
  7. readWriteAnyDatabase: 赋予用户所有数据库的读写权限,只在admin数据库中可用
  8. userAdminAnyDatabase: 赋予用户所有数据库管理User的权限,只在admin数据库中可用
  9. dbAdminAnyDatabase: 赋予管理所有数据库的权限,只在admin数据库中可用
  10. root: 超级账号,超级权限,只在admin数据库中可用。

集群管理角色

  1. clusterAdmin: 赋予管理集群的最高权限,只在admin数据库中可用
  2. clusterManager: 赋予管理和监控集群的权限
  3. clusterMonitor: 赋予监控集群的权限,对监控工具具有 readonly 的权限
  4. hostManager: 赋予管理Server

数据导入导出

csc 导入 mongo

1
2
3
4
mongoimport -h [host] --port [port] -u [userName] -p [password] -d [dbName] -c [collectionName] --type csv --headerline  --file [importPath]

# 例子:
mongoimport -h 127.0.0.1 --port 7003 -u edudot -p abcd-1234 -d edudot -c users --type csv --headerline --file "D:\Users\Wenhao.Wu\Desktop\users.csv"

mongo 导出

1
2
3
4
mongoexport -h [host] --port [port] -u [userName] -p [password] -d [dbName] -c [collectionName] -f [字段,多个资源英文逗号分隔] --type=csv -o [exportPath] --query=[queryString] --limit=[limitNum]

# 例子:
mongoexport -h 127.0.0.1 --port 7003 -u admin -p abcd-1234 -d edudot -c fc_msg -f _id,category --type=csv -o "D:\Users\Wenhao.Wu\Desktop\test.csv" --query="{'_id':'asfd'}" --limit=500

参考文章

piaoxuexieMongoDB 创建用户 修改权限 修改密码 删除用户

Git常用命令

发表于 2018-01-05 更新于 2019-09-10 分类于 Git Hot: ℃
本文字数: 23 阅读时长 ≈ 1 分钟

Clone

1
2
3
4
git clone git@github.com:dotnetcore/WTM.git

## 快速 clone,本地已经存在的数据将直接从本地获取
git clone --reference olddir/ git@github.com:dotnetcore/WTM.git newdir/

Branch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

## 创建分支
git branch [newBranchName] [srcBranchName]

## 推送本地分支到远程服务器
git push --set-upstream origin [newBranchName]

## 切换分支
git checkout [branchName]

## 创建分支并切换
git checkout -b [newBranchName] [srcBranchName]

## 删除本地分支
git branch -d [branchName]

## 强制删除本地分支
git branch -D [branchName]

## 删除远程分支
git push origin :[branchName]

## 删除本地的远程分支
git branch -r -D origin/[branchName]

## 合并分支
# 将 feature/f1 分支合并到 develop 分支上
git checkout develop
git merge feature/f1

Tag

1
2
3
4
5
6
7
8
9
10
11
12

## 创建 Tag
git tag -a [tagName] [-m 'message']

## 推送本地标签到远程服务器
git push origin --tags

## 删除本地 Tag
git tag -d [tagName]

## 删除远程 Tag
git push origin :[tagName]

查看 git 操作历史

1
2
3
# 查看所有记录的 HEAD 历史
# 可以用于查找丢失的代码
git reflog

ASP.Net Mvc OutputCache 服务器端缓存清理

发表于 2017-07-14 分类于 ASP.NET Hot: ℃
本文字数: 1.3k 阅读时长 ≈ 1 分钟

前言

近日在看 ASP.Net Mvc 的源码,在 OutputCache 上遇到了点问题特地记录一下。
在最后知道如何清理服务器端缓存之后,有些同学可能会发现那一句代码可能在直观上与服务器端缓存在什么位置并没有直接的联系(手动捂脸)。

什么是 OutputCache

在现如今的系统架构设计中,几乎都用到了缓存来提升系统的响应速度。但是缓存又分为多种,根据缓存内容的时机区分,我将缓存分为:

  • 数据缓存:需要对缓存的内容进行逻辑上的处理,最后才响应给客户端;
  • 页面缓存:直接将缓存的内容响应给客户端;

根据我的理解 ASP.Net Mvc 中的 OutputCache 是属于页面缓存。其主要的作用是根据用户请求的 资源URI 及其 请求参数 来区分是否是同一个页面,并将返回的页面缓存到源服务器、代理服务器或者客户端中。

当缓存在源服务器时,如何手动清理服务器端缓存?

服务器端缓存是缓存在哪里?

要解决这个问题,首先就要知道当 Location = OutputCacheLocation.Server 时,页面是缓存什么位置?IIS?System.Web.Caching?等。

然而查阅完 OutputCache 相关的源码后并没有发现什么端倪。只能借助 google 来搜了,最终在 stackoverflow 找到了一个相关的问题。

By default OutputCacheLocation.Server simply means that the data is stored in IIS Worker Process memory space. if you enabled Kernel-Mode caching the data is stored in the Http.Sys driver memory space (which is an Operating System process, not IIS process).

In the case of Windows Azure Shared Caching, the data is serialized and stored in a special process on the Virtual Machine instance, that process is then responsible for managing and synchronization of the cached data between all of the Role instances.

haim770how-asp-net-mvc-outputcachelocation-server-works

根据@haim770 的描述,我们知道了 OutputCache 的服务器端缓存是缓存在 IIS 进程内的内存空间 的,当启用 Kernel-Mode 内核模式 后,会将页面数据缓存在 http.Sys driver 的内存空间;

如何清理服务器端缓存呢?

知道了服务器端缓存缓存的位置之后,我们很方便的就可以对缓存进行清理:
HttpResponse.RemoveOutputCacheItem(Url.Action(“Index”));

参考文章

haim770how-asp-net-mvc-outputcachelocation-server-works

团队开发中的 Git commit 规范

发表于 2017-06-30 分类于 Git Hot: ℃
本文字数: 448 阅读时长 ≈ 1 分钟

Git commit 规范

建议大家按照此规范编写 Git commit message。

  1. 标题使用祈使语气;
  2. 标题开头添加 commit type,并以一个空格分隔;
  3. 标题不要使用句号结尾;
  4. 标题不超过 70 个字符;
  5. 用一空行分隔标题与正文;
  6. 正文解释 why & what,而不是 how;
  7. 正文在 70 个字符处换行;
  8. 如果 commit 的内容比较多,建议分拆成多个 commit;
  9. 删除 Changes to be committed: 以其下面的 #;
  10. commit Type:
    • add ( 添加功能或文件 )
    • del ( 删除功能或文件 )
    • mod ( 修改功能或文件 )
    • fix ( 修复 bug [PS: 修复 bug 的描述中包含 Issue 的 ID,如:Issue #269] )
    • refactor ( 重构 )
    • performance ( 提升性能、优化 )
    • dependency ( 升级依赖项,如 .net 平台的 nuget 包,node 的 node_modules 等 )
    • docs ( 修改文档 )

规范的 git commit message:

1
2
3
4
5
6
7
8
9
10
11
add 添加博客发布脚本
Changes to be committed:
new file: deploy.sh

mod 修改分数人数分布图批次线样式
Changes to be committed:
modified: Web/Views/Innovate/Index.cshtml

fix 修复数说报考迁徙图不分文理科
Changes to be committed:
modified: Web/Controllers/InnovateController.cs

参考文章

oschinaGit 提交的正确姿势:Commit message 编写指南
12
Vito

Vito

取是能力,舍是境界
14 日志
10 分类
31 标签
GitHub WTM E-Mail
京ICP备16041040号-1 © 2016 – 2023 Vito | 站点总字数: 8k | 站点阅读时长 ≈ 8 分钟
由 Hexo 强力驱动 v3.9.0
|
主题 – NexT.Mist v7.3.0
| 友情链接: 卡拉云后台系统
|