@cap-js/change-tracking

中文文档
2.2.3发布于 2026/10/09Apache-2.0CommonJS零依赖构建来源已验证近 30 天下载 6.7万

CDS插件提供框外支持,用于自动捕获,存储,并查看模型实体的更改记录.

中文使用文档
文档目录31 节
  1. 为什么此插件同时为 CAP 节点和 CAP Java 工作
  2. 目录
  3. 试试吧
  4. 说明
  5. 测试
  6. 详细解释
  7. 人类可读类型和领域
  8. 可读身份证
  9. 人类可读价值
  10. 人可读的构成条目标识
  11. 追踪任何变化
  12. 高级选项
  13. 已更改的表格视图
  14. 禁用懒惰装入
  15. 禁用 UI Facet 生成
  16. 禁用关联以更改生成
  17. 禁用更改跟踪
  18. 选择要跟踪的更改类型
  19. 保存已删除数据的更改日志
  20. 调整实体层级跟踪的深度
  21. 禁用儿童改变链接
  22. 实例
  23. 追踪变化
  24. 别
  25. 解决问题
  26. 直接修改数据库上的记录在升级到版本2后失败
  27. 带有语句级 HANA 触发器的“无效 RID 地址”出错
  28. 在本地启动持续 SQLite 数据库时“ 无” 错误
  29. 捐款
  30. 行为守则
  31. 许可证发放

SAP云应用程序编程模型(CAP)的更改跟踪插件

A 类 CDS 插件 用于自动捕获、储存和查看模拟实体的变化记录.

REUSE status

[大 有了2.0版,我们完全重构了如何追踪变化。 此前,逻辑依赖于应用层,该层限制了可追踪查询的类型,并在较大的项目中带来了重大的性能处罚. V2.0的更改现在通过数据库触发器在数据库层上得到充分跟踪。 此外,用v2.0清理了表格中的变化定义。 这意味着任何升级都涉及计划改变.

为什么此插件同时为 CAP 节点和 CAP Java 工作

此插件已执行为 CDS 插件 ——接通CDS建设管线的Node.js包. 在建造期间,它会产生 本地数据库触发器 (SQL DDL)直接取自CDS模型. 由于触发器在数据库级别运行,它们完全独立于应用程序运行时间:无论是CAP Node.js还是CAP Java都需要在请求时间做任何特殊的工作来捕捉变化.

说明@changelog)在构建时被插件解释一次,产生的触发器会随同计划一起被部署. 向履带式表格写作的任何应用程序——无论运行时间如何——都将自动由数据库记录其变化.

目录

试试吧

为启用更改跟踪, 只需在您的工程中添加此自配置插件包并添加 @changelog 数据模型的注释,如 详细解释。 。 。 .

npm add @cap-js/change-tracking

或者,在 tests/bookshop 文件夹 :

git clone https://github.com/cap-js/change-tracking
cd change-tracking
npm i
cd tests/bookshop
cds watch

用于 CAP Java 测试, 只需执行 mvn cds:watch 改为 cds watch。 。 。 .

[! 警告]

请注意,如果您的项目是多租户的,那么CDS版本必须高于8.6,mtx版本必须高于2.5,用于更改跟踪到工作.

[! 警告]

在使用MTX的多租期时,生成的数据库触发器,侧面和关联必须由MTX组件的模型提供者来创建. 因此,插件还必须添加到 package.json mTX侧车.

说明

[尖叫声] 请记住 敏感 或者说 个人 数据 (附加说明) @PersonalData)没有跟踪更改,因为查看日志可以让用户规避 审计-博客。 。 。 .

你需要做的是确定什么是应该通过在模型中标注相应的实体和要素来进行更改 @changelog 注释。 紧接着 将关注事项分开的最佳做法,我们在单独的文件中这样做 db/变化跟踪.cds数字 :

using { sap.capire.Incidents, sap.capire.Conversations } from './schema.cds';

annotate Incidents {
  customer @changelog: [customer.name];
  title    @changelog;
  status   @changelog;
}

annotate Conversations with @changelog: [author, timestamp] {
  message  @changelog @Common.Label: 'Message';
}

我们为追踪变化需要的最小说明是 @changelog 关于要素,关于要素 title 财务报告和审定财务报表 status 上面的样本片段.

可添加额外的标识符或标签以获取更多 人可读 变动记录如下.

测试

通过上述步骤,我们成功地为我们的参考应用建立了变革跟踪。 让我们看看行动.

  1. 启动服务器数字 :
cds watch
  1. 做点改变 在您更改的元素中。 数据库表将自动维持这一变化(sap.changelog.Changes,并以预先界定的观点提供,即: 更改历史视图 为了你的方便.

更改历史视图

change-history

如果您有 Fiori Element 应用程序, CDS 插件会自动提供并生成视图 sap.changelog.ChangeView,其外观会自动添加到您更改跟踪的实体/元素的Fiori对象页上。 在UI中,这与 更改历史 用于帮助您查看和搜索您建模实体所存储的更改记录的表格.

详细解释

人类可读类型和领域

默认情况下, 执行检查 对象类型 名称或 外地 来自各自名称 @title 或者说 @Common.Label 注释并使用技术名作为倒置.

例如,没有 @title 注释,对对话条目的更改将随技术实体名称出现:

change-history-type

加上注解 和可能的i18n这样的翻译:

annotate Incidents.conversations with @title: '{i18n>CONVERSATION}';

我们有一个人读的展示 对象类型数字 :

change-history-type-hr

可读身份证

更改日志注释 对象标识 定义在实体一级.

拥有一个 @changelog 没有附加标识符的注释, 对话条目的更改显示为简单的实体ID :

change-history-id

但是,这不可取,而且可读性可以提高,但明确的对象ID如下:

annotate Incidents.conversation with @changelog: [author, timestamp];
change-history-id-hr

注释接受路径列表,意指以下例子也是可能的: :

type CustomType : String;

extend Customers with elements {
  note: CustomType
}

annotate Incidents with @changelog: [
  title, customer.note, urgency.name
];
annotate Incidents with @changelog: [
  customer.address.city, customer.address.streetAddress, status.criticality
] {
  title    @changelog;
}

NULL 值对象ID倒置

何时 有点 @changelog 字段为无效,对象 ID 显示 <empty> 对于缺失的数值:

annotate Orders with @changelog: [customer, region];

如果区域无效, 对象ID将显示为 ACME Corp, <empty>当全部 @changelog 字段是无效的,对象ID会倒回实体的主密钥.

人类可读价值

更改日志注释 新值 财务报告和审定财务报表 旧值 定义为元素级别.

除非 @changelog 定义无法像类型那样进行唯一映射 enum 或者说 Association。 。 。 .

例如,拥有 @changelog 事件说明 customer 字段中没有任何额外的标识符,更改将显示为UUID:

customer @changelog;
change-history-value

因此,在此必须增加一个独特的标识符,以获得人可读值栏:

customer @changelog: [customer.name];
change-history-value-hr

人可读的构成条目标识

当修改一个子实体时,在母实体上创建一个构成变化日志条目 valueDataType = 'cds.Composition'编辑 对象标识 本条目列出受影响的情况。 如何解决对象ID取决于构成是否是 一人的组成 或一个 成员数目。 。 。 .

一人的组成

对于一个的构成,对象ID来源于 儿童实体 @changelog 注释。 如果儿童实体没有 @changelog,它掉回到 母实体 @changelog任意 @changelog 对对象ID不考虑对组成字段本身的注释.

@changelog: [name]
entity BookStores {
  key ID   : UUID;
  name     : String;
  registry : Composition of one BookStoreRegistry @changelog: ('Not considered');
}

@changelog: [code]
entity BookStoreRegistry {
  key ID      : UUID;
  code        : String;
  validOn     : Date @changelog;
}

何时 validOn 更改于 BookStoreRegistry,在 BookStores 将会有 objectID = 'TEST-REG' (从儿童 @changelog: [code]),不是家长的 name。 。 。 .

成员

对于多人的构成,对象ID是 没有 来源于儿童实体,因为不同的儿童可以有不同的识别特征。 相反,它又回到了 母实体 @changelog 注释.

@changelog: [name]
entity BookStores {
  key ID : UUID;
  name   : String;
  books  : Composition of many Books on books.bookStore = $self @changelog;
}

@changelog: [title]
entity Books {
  key ID    : UUID;
  bookStore : Association to BookStores;
  title     : String @changelog;
}

当a Books 条目被修改, 构成条目在 BookStores 将会有 objectID = 'Shakespeare and Company' (来自父母的) @changelog: [name]) (中文(简体) ).

您可以使用 @changelog 带有路径或表达. 注释 只能引用母实体的元素,而不是从儿童实体.

基于路径 :

annotate BookStores with @changelog: [name] {
  books @changelog: [name];  // uses parent's 'name' as Object ID
}

基于表达式 :

annotate BookStores with @changelog: [name] {
  books @changelog: ('Books from ' || name);  // evaluates to e.g. 'Books from Shakespeare and Company'
}

[注] 当在一个交易中创建或删除多个孩子时,每个父母只创建一个组成条目. 这个 modification 组合父条目上的类型总是 update,无论儿童是被创造、更新还是被删除。 这是因为单项交易可能涉及针对不同孩子的多类操作,因此无法指定单一的准确修改类型. 实际修改类型反映在儿童条目中.

以下变动日志的结果: Change Tracking Composition of many children

基于表达式的标签

除了平坦的道路之外 @changelog 注释支持计算人可读标签的CDS表达式. 表达式必须用括号包裹 () 将它们与路径区分开来:

annotate Incidents {
  status @changelog: (status.code || ': ' || status.descr);
  price  @changelog: (price < 100 ? 'Budget' : 'Premium');
}

何时 status 从 N (新)改为 R (已解决),标签将显示 "N: New" 财务报告和审定财务报表 "R: Resolved" 而不是原始键值。 对于 price,一个三进制表达式将数值分类为可被人读取的类别.

本地化价值

如果一个可被人类读取的值被附加了更改日志的注释,它就会被本地化.

extend Incidents with elements {
  status: Association to one Status @changelog: [status.descr];
}

entity Status {
  key code: String(1);
      descr: localized String(20);
}

默认情况下,为更改所存储的值标签以导致更改的用户的语言本地化. 指如果一个德语使用者改变状态,人可读值默认为德文.

与以上一样,人类可读值只包含一个字段,针对一个本地化的地产,并沿着(非)被管理的协会走,则使用动态人可读值,指如果一个说英语的用户查看变化,则该值标签将以英语显示,为法语等法语的用户使用.

追踪任何变化

使用数据库触发器执行更改跟踪,并支持HANA Cloud,SQLite和Postgres.

调用数据库触发器是指无论在服务中表现如何,任何变化都会被跟踪. 因此,跟踪通过工会或通过加入的意见而做出的改变仍将是可行的.

跟踪有固定时区的日期字段

该插件支持当字段有时区注释时跟踪日期时间字段变化.

extend Incidents with elements {
  closedAt : DateTime @changelog @Common.Timezone : 'Europe/Berlin';
  openedAt : DateTime @changelog @Common.Timezone : openedTimeZone;
  openedTimeZone : String @Common.IsTimezone;
}

在这两种情况下,插件将显示两个字段变化的附加说明的时区值。 在第二种情况下,动态取出时区,对时区字段的修改也将反映在该字段的变化记录中.

高级选项

已更改的表格视图

这个 更改历史 视图可以通过简单的修改或扩展来方便地适应和配置自己的需要。 比如,我们假设我们只想 显示前5个列 在平等间隔,我们会延伸 db/change-tracking.cds 内容如下:

using from '@cap-js/change-tracking';

annotate sap.changelog.ChangeView with @(
  UI.LineItem : [
    { Value: modificationLabel },
    { Value: createdAt },
    { Value: createdBy },
    { Value: entityLabel },
    { Value: objectID }
  ]
);

在UI里,我们 更改历史 现在的表格中仅包含五个具有理想属性的列:

change-history-custom

有关添加Fiori说明的更多信息和实例,见 添加 SAP Fiori 说明。 。 。 .

禁用懒惰装入

禁用懒惰加载特性 更改历史 在表格中,您可以添加以下注释: db/change-tracking.cds数字 :

using from '@cap-js/change-tracking';

annotate sap.changelog.aspect @(UI.Facets: [{
  $Type : 'UI.ReferenceFacet',
  ID    : 'ChangeHistoryFacet',
  Label : '{i18n>ChangeHistory}',
  Target: 'changes/@UI.PresentationVariant',
  @UI.PartOfPreview
}]);

系统现在使用 SAP Fiori 元素默认设置 @UI.PartOfPreview: true,这样,在浏览对象页时,表格将始终显示.

禁用 UI Facet 生成

如果您不想要自动提供的用于查看更改的 UI 面板, 您可以为您提供自己的面板 changes 协会 @UI.Facets 注释和插件不会覆盖它.

此外,如果您将协会评为不可读,则该面值也不会被添加。 你可以做到这一点,比如

@Capabilities.NavigationRestrictions.RestrictedProperties : [
  {
    NavigationProperty : changes,
    ReadRestrictions : {
      Readable : false,
    },
  },
]
entity SalesOrders {
  key ID : Int16;
      title  : String @changelog;
}

禁用关联以更改生成

某些假设情景,例如: UNION 编辑 @changelog 注释仍在宣传,协会自动加入 changes 这没有道理。 你用得着 @changelog.disable_assoc 用于在实体一级被禁用.

[大 这也将抑制UI面的添加,因为改变视图不再作为目标实体提供.

禁用更改跟踪

何时 @changelog 定义在底部的 DB 实体上,所有显示该实体的服务都会自动跟踪由于 注释传播启用 @changelog: false 在服务、实体或元素级别有选择地选择不跟踪.

// db/schema.cds — tracked across all services by default
@changelog: [title]
entity Incidents : cuid, managed {
  title    : String @changelog;
  date     : Date @changelog;
}
// srv/services.cds
service ProcessorService {
  entity Incidents as projection on db.Incidents;
}

// Disable tracking for the entire admin service
@changelog: false;
service AdminService {
  entity Incidents as projection on db.Incidents;
}

// Disable tracking for a specific projection only
service ReportingService {
  @changelog: false
  entity IncidentStats as projection on db.Incidents;
}

// Disable tracking for a specific element only
annotate ProcessorService.Incidents with {
  date @changelog: false;
}

选择要跟踪的更改类型

如果您不想跟踪某些类型的变化, 您可以使用 disableCreateTracking, (中文(简体) ), disableUpdateTracking 财务报告和审定财务报表 disableDeleteTracking 项目设置中的配置 :

{
  "cds": {
    "requires": {
      "change-tracking": {
        "disableCreateTracking": true,
        "disableUpdateTracking": false,
        "disableDeleteTracking": true
      }
    }
  }
}

保存已删除数据的更改日志

默认情况下,删除一个记录也会自动删除所有相关的更改日志. 这有助于减少对数据库规模的影响. 您可以通过添加以下切换到 package.json 您的项目

"cds": {
  "requires": {
    "change-tracking": {
      "preserveDeletes": true
    }
  }
}

[大 保留被删除数据的更改日志可对更改日志表的大小产生重大影响,因为现在这类数据也活过自动数据保留运行. 您必须执行自己的 数据保留战略 用于管理数据库的大小和性能.

调整实体层级跟踪的深度

默认情况下,任何实体的改变等级的深度为3. 这意味着,其变化以及其构成的变化和其构成的构成在UI上显示.

"cds": {
  "requires": {
    "change-tracking": {
      "maxDisplayHierarchyDepth": 3
    }
  }
}

[大 分级的深度具有性能影响,所以要注意增加分级!

禁用儿童改变链接

默认情况下,当一个构成中的子实体被改变跟踪时,会在母实体上创建额外的更改日志. 这个记录 valueDataType = 'cds.Composition' 编辑 attribute 设置为构成字段名(例如). conversation) (中文(简体) ). 它将从孩子到父母的改变联系起来,并允许对组成树的改变进行分级查看.

要禁用此连接特定构成的行为, 请将构成字段与 @changelog: false数字 :

entity Incidents : cuid, managed {
  title : String @changelog;
  @changelog: false
  conversation : Composition of many {
    key ID    : UUID;
    timestamp : type of managed:createdAt;
    author    : type of managed:createdBy;
    message   : String @changelog;
  };
}

与 @changelog: false 关于组成字段,儿童实体的个别变化(例如: message)仍然被跟踪,但是在母体上没有创建链接的更改日志. 这意味着孩子的改变不会出现在父母的改变历史等级中.

实例

本节介绍供进一步参考的模拟案例,从简单到复杂,包括:

追踪变化

使用大小写跟踪更改

使用例 1: 从当前实体中追踪子节点的变化, 并显示从子节点( 组合关系) 中获取的有意义的数据

模拟 db/schema.cds

entity Incidents : managed, cuid {
  ...
  title          : String @title: 'Title';
  conversation   : Composition of many Conversation;
  ...
}

aspect Conversation: managed, cuid {
    ...
    message   : String;
}

添加以下内容: @changelog 说明 db/change-tracking.cds

annotate Incidents with @changelog: [title] {
  conversation @changelog;
}

annotate Conversation with @changelog: [message] {
  message @changelog;
}

当a Conversation 条目被修改, 组成更改日志条目在 Incidents 将自动使用孩子的 对象标识 来源于 Conversation @changelog: [message]。这样,父的更改历史会显示哪个对话受到影响.

使用案例2:从当前实体中追踪关联实体的变化并显示关联实体的有意义的数据(关联关系)

模拟 db/schema.cds

entity Incidents : cuid, managed {
  ...
  customer       : Association to Customers;
  title          : String @title: 'Title';
  ...
}

entity Customers : cuid, managed {
  ...
  email          : EMailAddress;
  ...
}

添加以下内容: @changelog 说明 db/change-tracking.cds

annotate Incidents with @changelog: [title] {
  customer @changelog: [customer.email];
}

使用案例3:从当前实体中追踪链条关联实体的变化并显示关联实体的有意义的数据(关联关系)

模拟 db/schema.cds

entity Incidents : cuid, managed {
  ...
  title          : String @title: 'Title';
  customer       : Association to Customers;
  ...
}

entity Customers : cuid, managed {
  ...
  address : Composition of one Addresses;
  ...
}

添加以下内容: @changelog 说明 db/change-tracking.cds

annotate Incidents with @changelog: [title] {
  customer @changelog: [customer.address.city, customer.address.streetAddress];
}

改变跟踪支持从当前实体分析链式关联实体,以防该实体在消费者应用中是纯关系表. 然而,由于业绩成本,不建议使用连锁联系实体.


别

使用例 1: 不跟踪字段的变化 Association to many

entity Customers : cuid, managed {
  ...
  incidents : Association to many Incidents on incidents.customer = $self;
}

原因是: 关系: Association to many 数据库表格中没有具体字段。 在上述样本中,表中没有关于事故的一栏,但客户OData实体元数据中有事故的导航属性.

使用例2:不跟踪字段的变化 无管理协会

entity AggregatedBusinessTransactionData @(cds.autoexpose) : cuid {
    FootprintInventory: Association to one FootprintInventories
                        on  FootprintInventory.month                      = month
                        and FootprintInventory.year                       = year
                        and FootprintInventory.FootprintInventoryScope.ID = FootprintInventoryScope.ID;
    ...
}

原因是:在向关系数据库部署时,协会被映射到外国密钥. 然而,当映射到非关系数据库时,它们只是参考. 详情请查阅 优先管理协会。在上述样本中,表中没有Footprint Information的一栏,但OData实体元数据中有导航属性Footprint Information.

解决问题

直接修改数据库上的记录在升级到版本2后失败

数据库触发了变化跟踪杠杆会话上下文,以获取用户编号 createdBy 字段.

在哈纳 session_context('APPLICATIONUSER') 正在使用中。 所有通过 CAP 数据库驱动的查询 @cap-js/hana 将有背景。 在HANA Cloud Cockpit中,它也设定为用户登录的.

在邮政上 current_setting('cap.applicationuser', true) 正在用于获取用户信息,并再次获取所有通过查询 @cap-js/postgres 有背景.

在 SQLite 上不存在会话上下文函数 。 这样 @cap-js/sqlite 定义名为 UDF 的 UDF session_context 从数据库客户端查看会话背景 @cap-js/sqlite。如果您手动插入到 SQLite 中绕过 CAP 驱动程序,请确保定义 UDF .

带有语句级 HANA 触发器的“无效 RID 地址”出错

语句级触发器可能导致某些HANA版本的"无效的RID地址"出错. 这个问题与 HANA 版本已固定 2026.2.17 (中文(简体) ) (中文(简体) ). 如果您遇到此错误, 请将您的 HANA 实例升级为至少这个版本 .

作为临时工作,可以通过设置 rowLevelTriggers 工程配置中的旗帜 :

"cds": {
  "requires": {
    "change-tracking": {
      "rowLevelTriggers": true
    }
  }
}

[注] 行级触发器比语句级触发器慢,尤其是针对散装操作. 这个 rowLevelTriggers 旗帜是一个临时工作,将在未来的版本被删除.

在本地启动持续 SQLite 数据库时“ 无” 错误

当使用基于文件的SQLite数据库(例如. db.sqlite)对于本地开发,启动服务器可能因错误而失败,例如:

Error: no such table: main.SAP_CAPIRE_BOOKSHOP_BOOKS in:
CREATE TRIGGER IF NOT EXISTS SAP_CAPIRE_BOOKSHOP_BOOKS_ct_create AFTER INSERT ...

CAP 只在服务器启动时自动部署计划 记忆 SQLite (英语). 对于持续存在的 SQLite 文件,您必须在启动服务器前自行部署此方案, 否则更改跟踪插件无法在( 丢失) 应用程序表中创建其触发器 :

cds deploy
cds watch

见CAP文件 使用持久的 SQLite 数据库 详细情况.


捐款

此项目可通过下列方式对特性请求/建议、错误报告等开放: GitHub 问题鼓励并始终欢迎各方作出贡献和反馈。 关于如何作出贡献的更多信息,项目结构以及额外贡献信息见我们 贡献准则。 。 。 .

行为守则

作为成员、贡献者和领导人,我们保证使参加我们的社区成为每个人不受骚扰的经历。 通过参与这个项目,你同意遵守 行为守则 在任何时间.

许可证发放

版权2023 SAP SE或SAP下属公司和贡献者。 请看我们的 自由主义 版权和许可证信息。 详细信息,包括第三方组成部分及其许可证/版权信息 通过REUSE工具。 。 。 .

版本与发布记录

@cap-js/change-tracking 共发布 39 个版本,首次发布于 2023/10/18;过去 12 个月发布了 26 个版本。最新版本附带 npm provenance 构建来源证明,可追溯到公开的 CI 构建记录。

版本发布日期距今
2.2.3latest2026/10/0930 天前
2.2.22026/09/022 个月前
2.2.12026/08/272 个月前
2.2.02026/08/192 个月前
2.1.02026/07/283 个月前
2.0.32026/07/213 个月前

其他发布通道:beta → 2.0.0-beta.13。

关于 @cap-js/change-tracking 的常见问题

@cap-js/change-tracking 是什么?

CDS插件提供框外支持,用于自动捕获,存储,并查看模型实体的更改记录.

如何安装 @cap-js/change-tracking?

在项目目录运行 npm install @cap-js/change-tracking,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:@sap/cds(>=8.5)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@cap-js/change-tracking 支持 TypeScript 吗?

该包的 package.json 没有声明类型入口。需要类型提示时,可以在 npm 上查找社区维护的 @types/cap-js__change-tracking 是否存在。

@cap-js/change-tracking 支持 ESM 还是 CommonJS?

以 CommonJS 形式发布,可以直接 require();在 ES Module 项目中也可以用 import 引入(Node.js 会把 module.exports 作为默认导出)。

@cap-js/change-tracking 可以商用吗?

@cap-js/change-tracking 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@cap-js/change-tracking 的下载量有多少?

根据 npm 官方下载统计,@cap-js/change-tracking 在 2026/10/09 – 2026/11/07 这 30 天内被下载 66,720 次,日均约 2,224 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@cap-js/change-tracking 还在维护吗?

最新版本 2.2.3 发布于 2026/10/09(30 天前);至今共发布 39 个版本,其中过去 12 个月发布了 26 个;首次发布于 2023/10/18。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。