diff --git a/CHANGELOG.md b/CHANGELOG.md
index be09299d022b28bd74c803d815ec1ce7d04e1eab..79d53583a9203d46e717928646fc46102ad1a7a3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,19 @@
 # 🚀 版本日志
 
+## 2.10.30
+
+### 🐞 解决BUG、优化功能
+
+1. 【server】修复 导入 gitea 仓库搜索、分页无法正常使用问题
+   (感谢 [@Smith](https://gitee.com/autools) [Gitee pr 175](https://gitee.com/dromara/Jpom/pulls/175) [Gitee pr 174](https://gitee.com/dromara/Jpom/pulls/174) )
+2. 【server】优化 镜像启动容器不填写运行命令行导致容器启动失败(部分低版本)
+   (感谢 [@失落的世界](https://gitee.com/marmotgo) [Gitee pr 176](https://gitee.com/dromara/Jpom/pulls/176) )
+3. 【server】修复 节点分发 webhook 输入框的错别字(感谢 @大灰灰 )
+4. 【server】修复 工作空间环境变量操作日志记录错误问题
+5. 【all】更新 fastjson2 版本
+
+------
+
 ## 2.10.29 (2023-03-10)
 
 ### 🐣 新增功能
@@ -56,13 +70,14 @@
 ### 🐞 解决BUG、优化功能
 
 1. 【all】升级 springboot 版本
-2. 【server】优化 系统自动同步 docker 已经安装的集群信息 
+2. 【server】优化 系统自动同步 docker 已经安装的集群信息
 3. 【server】更新 mysql maven 坐标:`mysql-connector-j`
 4. 【server】修复 构建产物模糊匹配二级剔除配置 `/` 无效
 
 ### ⚠️ 注意
 
-新增 docker 资产管理,系统会自动将已经存在的 docker 信息根据 host 去重同步到资产管理中(如果 host 存在多个工作空间将根据最后更新时间排序使用最新的一条数据)
+新增 docker 资产管理,系统会自动将已经存在的 docker 信息根据 host 去重同步到资产管理中(如果 host
+存在多个工作空间将根据最后更新时间排序使用最新的一条数据)
 
 更新后 docker、集群列表中状态如果出现:`信息丢失` 表示关联数据存在异常不能正常使用,需要删除对应数据重新关联
 
@@ -98,7 +113,7 @@
 
 ### ❌ 不兼容功能
 
-1. 【server】删除 弃用表 NODE_STAT 
+1. 【server】删除 弃用表 NODE_STAT
 2. 【server】删除 弃用表 SYSTEMMONITORLOG
 3. 【server】删除 相关表中的 strike 字段
 
@@ -142,7 +157,7 @@
 ### ⚠️ 注意
 
 由于新增 SSH 资产管理,之前ssh 配置如果引用的工作空间变量的配置信息可能将失效(作用域不同).
-如果仍需要变量信息还需要将对应的信息迁移到全局变量中才可以正常使用 
+如果仍需要变量信息还需要将对应的信息迁移到全局变量中才可以正常使用
 
 ------
 
diff --git a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java
index bbae0c53178c6c115e23ba048666f5f748b3746c..c01adb090311933cb34d343795a17d3cb0dd8435 100644
--- a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java
+++ b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java
@@ -26,9 +26,11 @@ import cn.hutool.core.convert.Convert;
 import cn.hutool.db.Page;
 import cn.hutool.http.HttpResponse;
 import cn.hutool.http.HttpUtil;
+import com.alibaba.fastjson2.JSON;
 import com.alibaba.fastjson2.JSONArray;
 import com.alibaba.fastjson2.JSONObject;
 import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -64,7 +66,7 @@ public class GiteaUtil {
     /**
      * 每页的数量,最大为 100
      */
-    private static final String PER_PAGE = "per_page";
+    private static final String LIMIT = "limit";
 
     /**
      * 获取 Gitea 用户名
@@ -90,26 +92,62 @@ public class GiteaUtil {
      * @return
      */
     public static Map<String, Object> getGiteaRepos(String giteaAddress, String token, Page page, String condition) {
-        HttpResponse reposResponse = HttpUtil.createGet(giteaAddress + "/api/v1/user/repos", true)
+        if(condition == null ){
+            HttpResponse reposResponse = HttpUtil.createGet(giteaAddress + "/api/v1/user/repos", true)
+                .form(ACCESS_TOKEN, token)
+                //.form(SORT, "newest")
+                .form(PAGE, page.getPageNumber())
+                .form(LIMIT, page.getPageSize())
+                // 搜索关键字
+                //.form("q", condition)
+                .execute();
+            String body = reposResponse.body();
+            Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + body);
+            // 所有仓库总数,包括公开的和私有的
+            String totalCountStr = reposResponse.header("x-total-count");
+            int totalCount = Convert.toInt(totalCountStr, 0);
+            //String totalPage = reposResponse.header("total_page");
+
+            Map<String, Object> map = new HashMap<>(2);
+            map.put("jsonArray", JSONArray.parseArray(body));
+            // 仓库总数
+            map.put("totalCount", totalCount);
+            return map;
+        }else{
+            return getGiteaReposSearch(giteaAddress,token,page,condition);
+        }
+    }
+    /**
+     * 获取 Gitea 用户仓库信息搜索
+     *
+     * @param giteaAddress Gitea 地址
+     * @param token        用户授权码
+     * @param page         分页参数
+     * @return
+     */
+    public static Map<String, Object> getGiteaReposSearch( String giteaAddress, String token, Page page, String condition) {
+        HttpResponse reposResponse = HttpUtil.createGet(giteaAddress + "/api/v1/repos/search", true)
             .form(ACCESS_TOKEN, token)
-            .form(SORT, "pushed")
+            .form(SORT, "created")
             .form(PAGE, page.getPageNumber())
-            .form(PER_PAGE, page.getPageSize())
+            .form(LIMIT, page.getPageSize())
             // 搜索关键字
             .form("q", condition)
             .execute();
         String body = reposResponse.body();
-        Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + body);
-
+        JSONObject jsonObject = JSON.parseObject(body);
+        JSONArray data = jsonObject.getJSONArray("data");
+        Assert.state(reposResponse.isOk(), "获取仓库信息错误:" + data.toString());
         // 所有仓库总数,包括公开的和私有的
-        String totalCountStr = reposResponse.header("total_count");
+        String totalCountStr = reposResponse.header("x-total-count");
         int totalCount = Convert.toInt(totalCountStr, 0);
-        //String totalPage = reposResponse.header("total_page");
 
         Map<String, Object> map = new HashMap<>(2);
-        map.put("jsonArray", JSONArray.parseArray(body));
+        map.put("jsonArray", JSONArray.parseArray(data.toString()));
         // 仓库总数
         map.put("totalCount", totalCount);
         return map;
+
     }
+
 }
diff --git a/modules/server/src/main/java/io/jpom/controller/system/WorkspaceEnvVarController.java b/modules/server/src/main/java/io/jpom/controller/system/WorkspaceEnvVarController.java
index c93945df4c458faf069cb6d1666c2635cc12b339..e0af49feefcdd684202eff8485686a6a4bde31b3 100644
--- a/modules/server/src/main/java/io/jpom/controller/system/WorkspaceEnvVarController.java
+++ b/modules/server/src/main/java/io/jpom/controller/system/WorkspaceEnvVarController.java
@@ -59,7 +59,7 @@ import java.util.List;
  */
 
 @RestController
-@Feature(cls = ClassFeature.SYSTEM_WORKSPACE)
+@Feature(cls = ClassFeature.SYSTEM_WORKSPACE_ENV)
 @RequestMapping(value = "/system/workspace_env/")
 public class WorkspaceEnvVarController extends BaseServerController {
 
diff --git a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
index a3940dde945a96036a501ccd83f2074f4a47abc9..aee57b98275953e0447241a808babf2f9f53bccb 100644
--- a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
+++ b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java
@@ -44,6 +44,7 @@ import io.jpom.service.outgiving.LogReadServer;
 import io.jpom.service.outgiving.OutGivingServer;
 import io.jpom.service.script.ScriptExecuteLogServer;
 import io.jpom.service.script.ScriptServer;
+import io.jpom.service.system.WorkspaceEnvVarService;
 import io.jpom.service.system.WorkspaceService;
 import io.jpom.service.user.UserPermissionGroupServer;
 import io.jpom.service.user.UserService;
@@ -104,6 +105,7 @@ public enum ClassFeature {
     SYSTEM_NODE_WHITELIST("节点白名单分发"),
     SYSTEM_BACKUP("数据库备份", BackupInfoService.class),
     SYSTEM_WORKSPACE("工作空间", WorkspaceService.class),
+    SYSTEM_WORKSPACE_ENV("环境变量", WorkspaceEnvVarService.class),
 
     SCRIPT("脚本模板", ScriptServer.class),
     SCRIPT_LOG("脚本模板日志", ScriptExecuteLogServer.class),
diff --git a/modules/sub-plugin/docker-cli/src/main/java/io/jpom/DefaultDockerPluginImpl.java b/modules/sub-plugin/docker-cli/src/main/java/io/jpom/DefaultDockerPluginImpl.java
index 4bccf52c12fb6e37f6c04e71e75577df35f249a0..b860ab3e462cfbe8cc90eade03612a864644a3f8 100644
--- a/modules/sub-plugin/docker-cli/src/main/java/io/jpom/DefaultDockerPluginImpl.java
+++ b/modules/sub-plugin/docker-cli/src/main/java/io/jpom/DefaultDockerPluginImpl.java
@@ -298,11 +298,18 @@ public class DefaultDockerPluginImpl implements IDockerConfigPlugin {
             }
             return map;
         }).ifPresent(hostConfig::withStorageOpt);
+
         // 命令
         List<String> commands = (List<String>) parameter.get("commands");
-        if (CollUtil.isNotEmpty(commands)) {
-            containerCmd.withCmd(commands);
-        }
+        Optional.ofNullable(commands).ifPresent(strings -> {
+            List<String> list = strings.stream()
+                .filter(StrUtil::isNotEmpty)
+                .collect(Collectors.toList());
+            if (CollUtil.isNotEmpty(list)) {
+                containerCmd.withCmd(list);
+            }
+        });
+
         containerCmd.withHostConfig(hostConfig).withExposedPorts(exposedPortList);
         CreateContainerResponse containerResponse = containerCmd.exec();
         //
diff --git a/pom.xml b/pom.xml
index 1de62fc467d16178a90f43ba2d5b77dac7be3762..2ccf1812af394c21a7bed3a3311e09147e271e1c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -66,7 +66,7 @@
         <maven.test.skip>true</maven.test.skip>
         <!--        <maven.javadoc.skip>true</maven.javadoc.skip>-->
         <hutool.version>5.8.11</hutool.version>
-        <fastjson2.version>2.0.21</fastjson2.version>
+        <fastjson2.version>2.0.24</fastjson2.version>
     </properties>
     <dependencies>
         <dependency>
diff --git a/web-vue/src/pages/dispatch/list.vue b/web-vue/src/pages/dispatch/list.vue
index 05eab2de0bfb0278af9da85a6716fdf665bc3445..327b0fca2f10e7d64022709236373c43be836385 100644
--- a/web-vue/src/pages/dispatch/list.vue
+++ b/web-vue/src/pages/dispatch/list.vue
@@ -343,7 +343,7 @@
               <a-icon type="question-circle" theme="filled" />
             </a-tooltip>
           </template>
-          <a-input v-model="temp.webhook" placeholder="构建过程请求,非必填,GET请求" />
+          <a-input v-model="temp.webhook" placeholder="分发过程请求,非必填,GET请求" />
         </a-form-model-item>
       </a-form-model>
     </a-modal>
@@ -653,7 +653,7 @@
               <a-icon type="question-circle" theme="filled" />
             </a-tooltip>
           </template>
-          <a-input v-model="temp.webhook" placeholder="构建过程请求,非必填,GET请求" />
+          <a-input v-model="temp.webhook" placeholder="分发过程请求,非必填,GET请求" />
         </a-form-model-item>
       </a-form-model>
     </a-modal>
diff --git a/web-vue/src/pages/ssh/ssh.vue b/web-vue/src/pages/ssh/ssh.vue
index 665d7c49a206642791d7ec2d3cc822989ffe31ce..c74199bc37fb2407eeba839bc7c41c07851e8251 100644
--- a/web-vue/src/pages/ssh/ssh.vue
+++ b/web-vue/src/pages/ssh/ssh.vue
@@ -54,7 +54,7 @@
             </a-menu>
           </a-dropdown>
 
-          <a-tooltip placement="topLeft" title="如果按钮不可用,请去 ssh 编辑中添加允许管理的授权文件夹">
+          <a-tooltip placement="topLeft" title="如果按钮不可用,请去资产管理 ssh 列表的关联中添加当前工作空间允许管理的授权文件夹">
             <a-button size="small" type="primary" :disabled="!record.fileDirs" @click="handleFile(record)">文件</a-button>
           </a-tooltip>
           <a-dropdown>