复制文件及其整个历史记录

dot*_*hen 4 git

我和另一位开发人员正在开发由其他代码访问的API.当我们更改API的行为以更好地满足我们的需求时,我们会发布API的其他版本,而不会弃用旧版本,因此使用API​​的现有应用程序不必立即更新.例如:

$ cat 0.5.php
<?php
$username = $_POST['name'];
?>

$ cat 0.6.php
<?php
$username = $_POST['username'];
?>
Run Code Online (Sandbox Code Playgroud)

当我们开始新版本时,通常我们会将cpN-1.php版本化为N.php并从那里编写代码.然而,如果我们做到这一点使用Git,那么我们就丧失了整个blame,diff和其他历史从文件进行比较和恢复.我怎样才能"伪造"旧文件的这段历史进入新的文件,使得blame,log,diff,和这样的命令"只是工作",而不呈现给他们的其他标志或参数,如--follow

Joh*_*ter 10

你想使用这个-C标志.这将检测副本以及重命名,因此它可以跟踪历史记录. diff,blamelog接受这个标志.

就像@ madara-uchiha说的那样:你应该看看使用标签,也许可以git-x.y从他们那里生成你的文件.您可以使用以下内容来获取给定标记处文件的内容:

git show v0.6:git.php > git-0.6.php
Run Code Online (Sandbox Code Playgroud)

v0.6您感兴趣的标签在哪里?

更新:

这是一个小脚本.这第一个假设你的标签形式x.yx.y.z:

#!/bin/bash
versions=$(git tag -l | egrep -o '^[0-9]+\.[0-9]+(\.[0-9]+)?$')
for version in $versions
do
    git show $version:git.php > git-$version.php
done
Run Code Online (Sandbox Code Playgroud)

如果你的标签是形式vX.YvX.Y.Z你想要的git-x.y.phpgit-x.y.z.php作为文件名,这适用:

#!/bin/bash
versions=$(git tag -l | egrep -o '^v[0-9]+\.[0-9]+(\.[0-9]+)?$')
for version in $versions
do
    git show $version:git.php > git-${version/#v/}.php
done
Run Code Online (Sandbox Code Playgroud)

在发布过程中运行此脚本,它将为您生成所有版本.此外,git-从名称中删除它很容易.例如,> git-$version.php成为> $version.php.


Dav*_*dom 6

我认为你有点混淆,因为你似乎试图将版本控制处理事物的方式与API暴露的方式结合起来(即Web服务器如何处理事情).

为了使API的多个版本同时工作,消费者可能需要指定他们想要用于给定调用的版本.出于本答案的目的,我假设您的工作方式与Stack Exchange API类似,因此将版本指定为API URL的第一个"目录"组件(例如,对于版本1.5,我将我的请求指向http://domain.tld/1.5/call,我使用的版本1.6 http://domain/1.6/?method=call等等).但实际上这个元素并不重要,只要你有一些机制来确定适当的版本并将请求路由到Web服务器级别的正确控制器.

版本控制

我在这里采取的方法相当简单.每个版本都在存储库中获得自己的分支.针对该版本执行的任何开发工作都可以在版本分支的分支中完成,也可以直接提交到版本.Master总是包含最新的稳定版本.

例如,假设当前版本为1.5,并且所有内容当前都在master下,并且您没有历史分支.在当前稳定代码下绘制一条线,并创建一个名为1.5的分支.现在,要在1.6上开始开发,它将构建在1.5分支上,从master创建一个新分支并将其命名为1.6.

任何适用于1.6的开发都发生在1.6分支或使用1.6作为基础创建的其他分支中.这意味着一切都可以很好,干净地推入/拉入1.6分支.

如果您需要在1.5版本中应用小错误修复程序,则可以在1.5分支中轻松执行此操作.如果你想从1.6分支中提取,你需要"挑选"它 - 因为分支已经开始分歧,任何这样的问题都需要手动处理以确保最大限度地安全地保护"稳定" "代码库.

当创建1.7/2.0 /无论什么时候,将1.6版本拉入master,标记它,并为新版本创建一个新分支.

通过这种方式,每个版本/发行版的用户和时间的完整历史记录存储在分支中.正如其他人所提到的,不要忘记标记里程碑版本.

网络服务器

使用上述方法,Web服务器设置维护起来相当简单.每个版本的根目录都与相应的分支同步.

因此,为了简单起见,让我们想象一下,在版本控制库的根目录对应的API代码的文档根目录(实际上这是不太可能的情况下,但有点URL重写或类似的方法可以解决这个).

在Web服务器上的域的文档根目录中,我们创建以下目录结构:

<document-root>
    |
    |--- 1.5
    |
    |--- 1.6

在1.5,1.6目录中的每一个中,我们从中央版本控制克隆存储库,并切换到适当的分支.每次您希望实时更改时,只需从相应分支中的版本控制中下拉更改.

在高容量环境中,您可能必须致力于为每个版本与版本标识符作为一个子域的整体服务器,但相同的一般原则上适用 - 除了存储库可以直接克隆到每台服务器的文档根目录.

许多(如果不是全部)创造了新的分支目录,克隆回购了进去,并切换到适当的分支,以及拉下补丁的过程中/在发行版本bug修正,可以使用脚本/ cron的等自动化的,但在你这样做之前不要忘记:在没有人为参与的情况下将更改推送到实时服务器通常会以泪流满面.


另一种方法

...将创建一个单个父存储库,用作域的文档根.在此,您将在每个版本的存储库根目录中创建子模块.这将创建的整体效果将是相当类似,但有只具有同步的服务器上的单个存储库,并保持通过版本控制定义的Web服务器的目录结构中的"优势".但是,就个人而言,我不喜欢这种方法,原因有以下几点:

  • 子模块是一种难以维持的痛苦.它们附加到特定的提交中,很容易忘记它.
  • 我相信分支驱动方法提供的控制更精细,更准确地说明正在发生的事情.

我承认这两个原因在很大程度上都是个人偏好,这就是为什么我提出这个原因的可能性.