如何编写简单的版本控制系统?

时间:2009-06-09 21:43:03

标签: php sql algorithm data-structures code-organization

我想做一个简单的版本控制系统,但我没有关于如何构建我的数据和代码的想法。

这是一个简短的例子:

  1. 用户登录
  2. 上传文件时,用户有两个选项:
    • 提交新文件
    • 提交新版本的文件
  3. 用户应该能够看到树。 (不同的版本) 树只能达到2个级别:

    |
    |--File_A_0
     \--File_A_1
     \--File_A_2
     \--File_A_3
     \--File_A_4
    

    还有两种类型的文件,一种是final(最新批准的版本)和一种草稿版本(最新上传的文件) 该文件将物理存储在服务器上。 每个文件都由用户(或更多)拥有,只有一个组。

    编辑:群组代表一组文档,文档只能由一个群组一次拥有。用户不依赖于组。

    开始编辑:

    这就是我所做的,但效率并不高!

    id_article | relative_group_id | id_group | title | submited | date | abstract | reference | draft_version | count | status
    
    id_draft | id_file | version | date
    

    但是很难管理,扩展。 我认为这是因为小组参与者......

    结束修改

    所以问题是:

    • 我如何模式化我的数据库?
    • 什么样的信息应该有用 这个作品的版本?
    • 什么样的结构 文件夹,文件?
    • 你有什么样的提示,提示 做这种工作?

    (应用程序是用PHP和Zend Framework开发的,数据库应该是mysql或postgresql)

13 个答案:

答案 0 :(得分:49)

看在上帝的份上,不要。你真的不想走这条路。

停下来思考一下大局。你想保留早期版本的文档,这意味着在某些时候,有人会想要看到一些早期版本,对吧?然后他们会问,“版本3和版本7之间有什么区别”?然后他们会说,“我想回滚到版本3,但保持我在第5版中提出的一些更改,嗯,好吗?“

版本控制非常重要,并且不需要重新发明轮子 - 那里有许多可行的版本控制系统,其中一些是免费的,甚至是。

从长远来看,学习其中一个系统的API会更加容易,并且会为您的用户编写一个Web前端代码,为您的用户提供他们正在寻找的功能子集(现在。)

您不会为您的用户编写文本编辑器,是吗?

答案 1 :(得分:18)

你可以从there获得灵感。


关于您的评论:

对于数据库结构,您可以尝试这种结构(MySQL sql):

CREATE TABLE `Users` (
       `UserID` INT NOT NULL AUTO_INCREMENT
     , `UserName` CHAR(50) NOT NULL
     , `UserLogin` CHAR(20) NOT NULL
     , PRIMARY KEY (`UserID`)
);

CREATE TABLE `Groups` (
       `GroupID` INT NOT NULL AUTO_INCREMENT
     , `GroupName` CHAR(20) NOT NULL
     , PRIMARY KEY (`GroupID`)
);

CREATE TABLE `Documents` (
       `DocID` INT NOT NULL AUTO_INCREMENT
     , `GroupID` INT NOT NULL
     , `DocName` CHAR(50) NOT NULL
     , `DocDateCreated` DATETIME NOT NULL
     , PRIMARY KEY (`DocID`)
     , INDEX (`GroupID`)
     , CONSTRAINT `FK_Documents_1` FOREIGN KEY (`GroupID`)
                  REFERENCES `Groups` (`GroupID`)
);

CREATE TABLE `Revisions` (
       `RevID` INT NOT NULL AUTO_INCREMENT
     , `DocID` INT
     , `RevUserFileName` CHAR(30) NOT NULL
     , `RevServerFilePath` CHAR(255) NOT NULL
     , `RevDateUpload` DATETIME NOT NULL
     , `RevAccepted` BOOLEAN NOT NULL
     , PRIMARY KEY (`RevID`)
     , INDEX (`DocID`)
     , CONSTRAINT `FK_Revisions_1` FOREIGN KEY (`DocID`)
                  REFERENCES `Documents` (`DocID`)
);

CREATE TABLE `M2M_UserRev` (
       `UserID` INT NOT NULL
     , `RevID` INT NOT NULL
     , INDEX (`UserID`)
     , CONSTRAINT `FK_M2M_UserRev_1` FOREIGN KEY (`UserID`)
                  REFERENCES `Users` (`UserID`)
     , INDEX (`RevID`)
     , CONSTRAINT `FK_M2M_UserRev_2` FOREIGN KEY (`RevID`)
                  REFERENCES `Revisions` (`RevID`)
);

Documents是一个逻辑容器,Revisions包含指向文件的实际链接。 每当一个人更新一个新文件时,在每个表中创建一个条目,Revisions中的条目包含一个插入到Documents中的文章的链接。

表M2M_UserRev允许将多个用户关联到文档的每个修订版。

更新文档时,仅在“修订”中插入,并附加到相应的文档。要知道要链接到哪个文档,您可以使用命名约定,或要求用户选择正确的文档。

对于文件的文件系统架构,它确实没关系。我只是在将文件存储在服务器上之前将其重命名为独特的文件,并将用户文件名保存在数据库中。只需将重命名的文件存储在任何位置的文件夹中,并在数据库中保留它的路径。这样,您就知道如何在用户请求时重命名它。如果你确定它是唯一的,你也可以保留用户给出的原始名称,但我不会太依赖它。您可能很快就会看到两个不同的版本具有相同的名称,另一个会覆盖您文件系统中的另一个版本。

答案 2 :(得分:13)

数据库架构


为了保持极其简单,我会选择以下数据库设计。我将“文件”(与文件系统文件相同)概念与“文档”(文档的分层组)概念分开。

用户实体:

  • 用户id
  • 的userName

群组实体:

  • 的groupId
  • 组名

档案实体:

  • fileId(序列)
  • fileName(用户为文件指定的名称)
  • filesystemFullPath
  • uploadTime
  • uploaderId(上传者用户的ID)
  • ownerGroupId

文档实体:

  • documentId
  • parentDocumentId
  • FILEID
  • VERSIONNUMBER
  • 创建时间
  • isApproved

每次上传新文件时,都会创建“文件”记录,还会创建新的“文档”。如果是第一次上传该文件,则该文档的parentDocumentId将为NULL。否则,新文档记录将指向第一个版本。

“isApproved”字段(布尔值)将处理作为草稿或批准修订的文档。
您可以获得文档的最新草稿,只需按版本号或上传时间进行排序。

提示


从描述问题的方式来看,在转向数据库架构设计之前,应该更好地分析这些方面:

  • 这是“团体”实体的角色?
  • 群组/用户/文件如何相关?
  • 如果不同组的两个用户尝试上传同一文档会怎样?
  • 你需要文件夹吗? (可能你会;我的解决方案仍然有效,给“文件”实体提供一个类型,“文件夹”或“文档”)

希望这有帮助。

答案 3 :(得分:9)

现有的版本控制解决方案可能比滚动自己更好吗? Subversion可以做你想做的大部分事情,而且就在那里。

答案 4 :(得分:6)

在传统的关系数据库(如MySQL)中创建丰富的数据结构通常很困难,并且有更好的方法来实现它。使用具有层次结构的基于路径的数据结构时,我喜欢创建一个基于平面文件的系统,该系统使用数据序列化格式(如JSON)来存储有关特定文件,目录或整个存储库的信息。

通过这种方式,您可以使用当前可用的工具轻松导航和操作结构,并且您可以轻松地阅读,编辑和了解结构。 XML也适用于此 - 它比JSON稍微冗长,但易于阅读,也适用于消息传递和其他基于XML的系统。

一个简单的例子。如果我们有一个包含目录和三个文件的存储库。在它前面看它看起来像这样:

/repo
  /folder
    code.php
  file.txt
  image.jpg

我们可以拥有一个元数据文件夹,其中包含我们在操作系统中隐藏的JSON文件,这些文件位于每个目录的根目录下,用于描述该目录的内容。这是传统版本控制系统的工作方式,除了它们使用自定义语言而不是JSON。

/repo
  */.folderdata*
  /code
    */.folderdata*
    code.php
  file.txt
  image.jpg

每个 .folderdata 文件夹都可以包含它自己的结构,我们可以使用它来正确组织文件夹的数据。然后可以压缩每个 .folderdata 文件夹以节省磁盘空间。如果我们查看/ code目录中的 .folderdata 文件夹:

*/.folderdata*
  /revisions
    code.php.r1
    code.php.r2
    code.php.r3
  folderstructure.json
  filerevisions.json

文件夹结构定义了我们文件夹的结构,文件和文件夹彼此相关等等。这可能是这样的:

{
  '.':        'code',
  '..':       'repo',
  'code.php': {
    'author_id': 11543,
    'author_name': 'Jamie Rumbelow',
    'file_hash': 'a26hb3vpq22'
    'access': 'public'
  }
}

这允许我们关联该文件的元数据,检查真实性和完整性,保留持久数据,指定文件属性以及执行更多操作。然后,我们可以在filerevisions.json文件中保留有关特定修订的信息:

{
  'code.php': [
    1: {
      'commit': 'ah32mncnj654oidfd',
      'commit_author_id': 11543,
      'commit_author_name': 'Jamie Rumbelow',
      'commit_message': 'Made some changes to code.php',
      'additions': 2,
      'subtractions': 4
    },
    2: {
      'commit': 'ljk4klj34khn5nkk5',
      'commit_author_id': 18676,
      'commit_author_name': 'Jo Johnson',
      'commit_message': 'Fixed Jamie\'s bad code!',
      'additions': 2,
      'subtractions': 0
    },
    3: {
      'commit': '77sdnjhhh4ife943r',
      'commit_author_id': 11543,
      'commit_author_name': 'Jamie Rumbelow',
      'commit_message': 'Whoah, showstopper found and fixed',
      'additions': 8,
      'subtractions': 5
    },
  ]
}

这是文件版本控制系统的基本大纲计划 - 我喜欢这个想法以及它是如何工作的,并且我过去使用过JSON来实现这样丰富的数据结构。这种数据不适合像MySQL这样的关系型数据库 - 随着您获得更多修订和更多文件,数据库将变得越来越大,这样您就可以错开多个文件的修订,保留所有内容的备份,使确保你有跨接口和平台等的持久数据。

希望这给了你一些见解,希望它也能为社区提供一些思考的食物!

答案 5 :(得分:2)

对于数据库架构,您可能需要两组信息,文件和文件版本。存储新文件时,也会创建初始版本。必须明确存储最新批准的版本,而最新版本可以从版本表中选择(通过查找与文件相关的最高版本,或者如果在创建时存储,则为最新日期)

files(id,name,approved_version)
file_versions(id,fileId)
然后可以使用它们的ID(例如,'/ fileId / versionId'或'/ fileId / versionId_fileName')在服务器上存储

文件版本,其原始名称存储在数据库中。

答案 6 :(得分:2)

我最近为一些静态数据实体构建了一个简单的版本控制系统。要求是拥有“活跃”版本和0或1个待定版本。

最后,我的版本化实体具有以下与版本控制相关的属性。

VersionNumber(int / long) ActiveVersionFlag(布尔值)

其中: -

  • 只有1个实体可以是ActiveVersionFlag ='Y'
  • 只有1个实体可以是版本号> “活跃”版本(即“待定”版本)

我允许的操作类型是

克隆当前版本。

  • 如果已有版本>则失败“活动”版本的版本号
  • 将所有数据复制到新版本
  • 将版本号增加一个

激活待定版本

  • 如果指定的版本不是“活动”版本+ 1
  • ,则失败
  • 找到“有效”版本并将其ActiveVersionFlag设置为“N”
  • 将“待定”版本的ActiveVersionFlag设置为“Y”

删除待定版本

  • 删除待处理实体

这是相当成功的,我的用户现在一直克隆并激活:)

迈克尔

答案 7 :(得分:1)

从现有的content management system开始,在PHP和MySQL中完成,如果这些是您的要求,例如eZ PublishKnowledgetree。为了快速测试这些应用程序,Bitnami提供了快速安装“stacks”这些应用程序(类固醇上的WAMP堆栈)。

然后,您可以根据组织需求定制这些应用程序,并及时了解上游的变化。

答案 8 :(得分:1)

作为我上一篇文章的替代方案,如果您认为层次结构最好,您可能希望使用平面文件存储,并通过Web服务公开API。

服务器将拥有其数据根目录,您可以将文件组(文件)存储在文件夹中,每个文件夹中都有一个根元数据条目。 (也许是XML?)

然后,您可以使用包含在API中的现有修订控制工具,或者自己滚动,将文件的修订保留在文件夹中项目下方的修订文件夹中。检查修订,并使用文件I / O命令执行文件I / O.将API公开给Web应用程序或其他客户端应用程序,让服务器通过XML文件确定文件权限和用户映射。

迁移服务器?邮编和副本。 跨平台?邮编和副本。 备份?邮编和复制。

例如,这是我喜欢Mercurial DVCS的平面文件后端。

当然,在这个小例子中,.rev文件可能有revisions.xml文件中定义的日期,时间,压缩等。如果要访问其中一个修订版,则公开一个AccessFile()方法,服务器应用程序将查看revisions.xml,并确定如何打开该文件,是否授予访问权限等。

所以你有

DATA
| + ROOT
| | . metadata.xml
| | |
| | + REVISIONS
| | | . revisionsdata.xml
| | | . documenta.doc.00.rev
| | | . documenta.doc.01.rev
| | | . documentb.ppt.00.rev
| | | . documentb.ppt.03.rev
| | |___
| | |
| | . documenta.doc
| | . documentb.ppt
| | |
| | + GROUP_A
| | | . metadata.xml
| | | |
| | | + REVISIONS
| | | | . revisionsdata.xml
| | | | . documentc.doc.00.rev
| | | | . documentc.doc.01.rev
| | | | . documentd.ppt.00.rev
| | | | . documentd.ppt.03.rev
| | | |___
| | |
| | | . documentc.doc
| | | . documentd.ppt
| | |___
| | |
| | + GROUP_B
| | | . metadata.xml
| | |___
| |
| |___
|
|___

答案 9 :(得分:0)

结帐ProjectPier(原ActiveCollab)。它有一个与此类似的系统,您可以查看它们的来源。

答案 10 :(得分:0)

上传文件是1990-ty =) 看看Google Wave!您可以围绕其“版本控制”框架构建整个应用程序。

答案 11 :(得分:0)

它并不像看起来那么简单。阅读Eric Sink关于存储这些文件的影响的this article

也许更好的问题是加载什么类型的文件,它们是否适合版本控制(如文本文件)

答案 12 :(得分:0)

我认为这描述了完美的版本控制系统

http://tom.preston-werner.com/2009/05/19/the-git-parable.html