使用 Liquibase 和 Git 的推荐工作流程是什么?

2022-09-04 02:26:09

最近我们开始使用Liquibase。这还没有发生,但我们想象了如果两个开发人员将更改日志文件中的更改提交到共享的Git存储库会发生什么。

如何解决或避免合并冲突?为了扩大这个问题,一些什么:

将 Liquibase 与 Git 结合使用的推荐工作流程是什么?

示例场景:
- Michael 更改了表“客户”中的一列。
- 雅各布更改了表“帐户”中的一列。
因此,两个开发人员都向同一个更改日志文件添加了更改日志.xml。<changeSet>

编辑:

正如评论的那样,这种情况确实并不那么令人兴奋。假设雅各布是最后一个推送代码的人。他必须先拉。获取警告,说明有合并冲突需要解决。他通过保留代码的两个部分,迈克尔和他的代码来解决冲突。使用 Liquibase 更新数据库不会出现任何问题。

高级示例场景:
-Michael 更改“first_name”中表“客户”的列“name”的名称,提交并推送。
-Jacob 更改“last_name”中表“customer”的列“name”的名称并提交。
-Jacob 在提取 Michael 的代码时遇到合并冲突。
雅各布和迈克尔讨论了这场冲突,并同意它必须是“last_name”,雅各布承诺并推动。
- 迈克尔拉出已解决的冲突并运行Liquibase更新。他得到一个错误:column "name" does not exist


答案 1

在我的公司,我们使用液态碱的方式可以防止这些情况的发生。基本上,您可以为每个更改创建一个单独的 liquibase 文件。我们以发起更改的 JIRA 票证命名文件,并带有一些描述性文本。这些文件中的每一个,我们都将它们所在的系统版本放入一个文件夹中;如果下一个版本是1.22,那么当我们开始进行数据库更改时,将创建该文件夹,并将每个lquibase文件与一个更新.xml脚本一起放在那里,该脚本仅包含它们。该更新.xml文件最终成为唯一可能真正发生冲突的地方,并且它们很容易解决。

为了说明,这是文件夹:src/main/liquibase

├── install                        
│   ├── projectauthor.xml          
│   ├── project_obspriorities.xml  
│   ├── project_priorities.xml     
│   ├── project_udv.xml            
│   ├── project.xml                
│   ├── roles.xml                  
│   ├── scan.xml                   
│   ├── (the other table definitions in the system go here)
│
├── install.xml                 <-- this reads all the files in ./install
│
├── local.properties            <--
├── prod.properties             <--  these are database credentials (boo, hiss)  
├── staging.properties          <-- 
├── test.properties             <--  
│
├── update.xml                  <-- reads each version/master.xml file     
│
├── v1.16
│   ├── 2013-06-06_EVL-2240.xml
│   ├── 2013-07-01_EVL-2286-remove-invalid-name-characters.xml
│   ├── 2013-07-02_defer-coauthor-projectauthor-unique-constraint.xml
│   └── master.xml
├── v1.17
│   ├── 2013-07-19_EVL-2295.xml
│   ├── 2013-09-11_EVL-2370_otf-mosaicking.xml
│   └── master.xml
├── v1.18
│   ├── 2014-05-05_EVL-2326-remove-prerequisite-construct.xml
│   ├── 2014-06-03_EVL-2750_fix-p-band-polarizations.xml
│   └── master.xml

安装.xml文件只是一堆文件包含:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">

    <include file="src/main/liquibase/project/install/projectauthor.xml"/>
    <include file="src/main/liquibase/project/install/project_obspriorities.xml"/>
    ...
</databaseChangeLog>

更新.xml文件是相同的故事:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-2.0.xsd">
    <include file="src/main/liquibase/project/v1.18/master.xml"/>
</databaseChangeLog>

我不喜欢的工作流程的一个方面是,install/*.xml应该创建数据库,因为它在当前版本之前,但我们通常不记得这样做。

无论如何,这种方法将使您免于合并的很多悲伤。我们正在使用Subversion,并且这种方法没有任何合并困难。


答案 2

总有一些边缘情况需要手动处理,但它们通常很少发生。Git 通常可以很好地处理文本级别的更改合并,因此合并的文件将具有两个更改集,一个接一个。

由于 liquibase 按 id/author/filename 跟踪 changeSets,因此 Jacob 的 changeSet 恰好在最终 changeSet 中在 Michaels 之前结束的事实并不重要。当两个开发人员都运行最终的 changeSet 时,Liquibase 将运行另一个开发人员的 changeSet,只是因为他们的更改已标记为已运行,而另一个则未标记为已运行。对于所有其他环境,两个更改集都将运行。

您的高级案例遇到问题,因为两个开发人员都在进行相互矛盾的更改。如果两个开发人员都删除一列,或者添加具有相同名称的新列,您也可能遇到类似的问题。它并不总是简单地一个开发人员与另一个开发人员,有时冲突的更改集来自两个单独的功能分支被合并。合并的 changeSet 本身在物理上没有问题,问题是新的 changelog 在逻辑上不正确。这不是一个真正的git问题,而是一个逻辑问题。

在实践中,这种类型的冲突很少发生,因为不同的开发人员和不同的分支通常在代码库的不同区域上工作,当存在潜在的冲突时,他们通过通信和规划来处理它。

如果确实遇到冲突,有几种方法可以解决冲突。通常,这是通过删除不正确或重复的 changeSet 来处理的(如您的示例中所示),但也可以通过创建一个全新的 changeSet 来处理,该 changeSet 是两者的组合。在任一情况下,您都需要处理运行“错误”更改集的数据库。如何最好地处理它取决于有多少系统运行了它。

如果是单个开发人员,有时最简单的方法是运行以将新更改集标记为已运行,然后在数据库中手动进行更改。如果最近运行了错误的更改集,他们甚至可以运行以还原其错误的更改,然后删除更改集,然后liquibase changeLogSyncliquibase rollbackCount Xliquibase update

如果有多个冲突和/或多个系统运行了问题更改集,则最简单的方法通常是使用标记。您可以删除错误的 changeSet 并添加一个新的 changeSet,该 changeSet 仅在执行旧 changeSet 时运行,并将数据库放回以后的 changeSet 所期望的状态。在您的示例中,它会first_name重命名回 name,以便last_name changeSet 的名称工作正常。<preConditions onFail="MARK_RAN"><changeSetExecuted id=....></preConditions>


推荐