利用gitrepo无缝迁移git项目

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了利用gitrepo无缝迁移git项目相关的知识,希望对你有一定的参考价值。

参考技术A 正所谓天下大事合久必分,分久必合。实际工作中的项目也类似,有的项目越来越大,或者有时候需要把没有前后端分离的项目代码拆分到两个仓库里,就涉及到对已有git项目的迁移操作。

如果只是简单地把代码拆开并不难,可以选择直接下载git项目源代码压缩包,拆分后push到新建的git仓库里就可以了。

但是现实世界往往没有那么简单,比如正在进行的开发分支还没有合并,或者我们想保留提交记录和分支关系。如此种种原因导致无法简单粗暴地把源代码扔到一个新建的git仓库里,还涉及对git记录进行必要的裁剪。

本文就介绍一个好用的工具来进行无损的git仓库迁移。

在实际工作中,我们有一个项目,其项目目录结构很简单,是一个既含有前端代码,也含有服务端代码的仓库,如下所示:

我们希望将前端和服务端代码拆分成两个独立的git仓库,但是因为开发同学还有正在开发的功能分支没有合并,因此我们希望能够同时迁移代码和git提交 历史 以及分支。最终希望得到的结果是:

git repo A: ./server/

git repo B: ./webapp/

通过查看git文档,首先考虑使用git filter-branch命令来进行迁移。简单来说该命令可以用来操作目录树,同时修改 历史 提交记录。

在我还没来得及完全理解这个命令之前,就看到文档中有这样一段warning

这里提到了filter-branch命令由于有可能产生杂乱的提交 历史 ,以及惨不忍睹的执行效率,所以最终推荐了一个第三方工具git filter-repo。接下来,就该今天的主角登场了。

在github首页上,关于git-filter-repo有这样的描述

接下来我们考虑如何利用这个强大的工具来进行git项目的迁移。

首先,需要定义成功迁移的标准:

查看git-filter-repo的文档可以看到有不少简单的示例,很幸运有一些例子正好可以解决我们的问题。

git-filter-repo的命令选项 (flag) 主要用来操作目录树,根据操作的目录树自动判断需要修改的git提交 历史 信息。

比如我们需要保留webapp目录,删除server目录,那么仅需执行:

这样仓库中的目录结构就会变为:

可以看到,已经没有server文件夹了。

再比如如果我们希望删除.DS_Store文件以及其提交 历史 :

当然通常我们需要删除根目录下所有.DS_Store文件及其 历史 ,那么可以加上--use-base-name选项,表示匹配文件名,而不是匹配完整路径:

其中 --path 选项后跟需要操作的路径或者文件名,--invert-paths选项字面意思是反向,因此该标记表示的是删除操作。

以上都是删除某些文件或者保留某些文件的操作,其目录结构仍然会保留原始仓库的结构,但我们需要的是仅保留webapp目录下的所有文件,并将其中的内容移动到根目录下。针对这种场景git-filter-repo提供了一个叫做--subdirectory-filter的选项,接下来就进行实际操作。

接下来再看一下老的仓库目录结构

仅保留webapp目录下的内容,并让其成为新的根目录,执行如下命令:

执行结果的目录结构如下所示:

至此,目录结构已经如愿完成,为了确认迁移的 历史 记录也是完整的,执行

如果确认本地仓库的迁移结果正确,再执行命令将当前本地仓库推向迁移的目的仓库即可:

至此我们的git项目迁移就完成了,不仅将代码迁移到新的仓库,也同时将提交 历史 带去了新的仓库。这样一来,对于开发同学来说迁移完全是无痛的,只是切换了新的git地址,而开发过程完全不会中断。

在git项目需要迁移的场景中,日常工作中也许第一反应就是让开发同学们放下手中的工作,全部推向一个指定用于迁移的分支,然后以这个分支为准,下载源代码,再将其推送到新的仓库中。

这种操作方式虽然简单,但是对于开发同学来说,却会造成很多麻烦。

比如新仓库的代码不仅含有自己未开发完成的代码,也含有其他人未完成的代码,很有可能在迁移完成之后项目都跑不起来。

而除此以外,如果新仓库的代码有一个需要很快就上线的功能,或者紧急修复,面对一个百废待兴的新仓库,如何整理出一个可以上线的代码版本,又是一件非常头大的事情。

git-filter-branch可以帮助我们修改目录树和提交 历史 ,但是执行效率和混乱的提交 历史 显得太过于繁琐。

git-filter-repo工具提供了强大的工具集,良好的用户使用界面,以及高效率的处理机制,在目前确实是处理仓库迁移的最优选择。

本文仅仅是讲解了git-filter-repo的一种应用场景,其官方文档上有更多的使用场景,可以根据更多的条件来过滤和操作文件和提交 历史 。

Django 迁移失败

【中文标题】Django 迁移失败【英文标题】:Django Migrations Failing 【发布时间】:2020-05-29 17:56:09 【问题描述】:

我有两台用于 django 项目的开发机器 - 塔式和笔记本电脑。我使用私人 git 存储库来保持项目同步。我在塔上工作了一段时间,将更改提交到我的 git repo(包括数据库),然后执行 git pull origin master 和 git reset --hard origin/master,然后我在旅行时在笔记本电脑上工作。

我似乎在某个地方犯了一个错误,因为当我如上所述更新笔记本电脑时,我的迁移出现了错误。在塔上,所有迁移都是最新的并已应用。在笔记本电脑上,我有几个无法应用的迁移。

 [X] 0044_remove_document_rotation
 [ ] 0041_remove_collectiondocument_position
 [ ] 0045_merge_20191023_1922
 [X] 0045_auto_20191121_1536
 [ ] 0046_merge_20200213_1523
 [X] 0046_auto_20200213_1541
 [ ] 0047_merge_20200213_1546

这些迁移都在 Tower 上进行了检查。尝试在笔记本电脑上迁移时出现错误:

  Applying memorabilia.0041_remove_collectiondocument_position...Traceback (most recent call last):
  File "./manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/__init__.py", line 401, in execute_from_command_line
    utility.execute()
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/__init__.py", line 395, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/base.py", line 328, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/base.py", line 369, in execute
    output = self.handle(*args, **options)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/core/management/commands/migrate.py", line 233, in handle
    fake_initial=fake_initial,
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/migrations/executor.py", line 117, in migrate
    state = self._migrate_all_forwards(state, plan, full_plan, fake=fake, fake_initial=fake_initial)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/migrations/executor.py", line 147, in _migrate_all_forwards
    state = self.apply_migration(state, migration, fake=fake, fake_initial=fake_initial)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/migrations/executor.py", line 245, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/migrations/migration.py", line 114, in apply
    operation.state_forwards(self.app_label, project_state)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/migrations/operations/fields.py", line 172, in state_forwards
    delay = not old_field.is_relation
AttributeError: 'NoneType' object has no attribute 'is_relation'

该项目可在塔式电脑和笔记本电脑上运行。

如何在笔记本电脑上应用这些迁移,或删除导致问题的迁移?

【问题讨论】:

【参考方案1】:

当我遇到这样的同步问题时,作为最后的手段,我经常删除迁移并从头开始。为此:

    在迁移文件夹中创建所有迁移的备份(例如,0001.iniital.py 和 0002_auto_20191220_1357.py 以及 myproject/myproject/myapp/migrations/ 中的其他类似文件),然后将其删除。 转到您的 Django 数据库并删除 django.migrations 中的所有条目。 备份您的表,然后将它们从您的 MySQL(或其他)数据库中删除。

以上内容将为您提供一个完全干净的状态。

之后:

python manage.py makemigrations

接着是:

python manage.py migrate

如果您的模型设置正确,这将重新创建您的所有结构而不会出错。最后,检查备份的表,并在没有差异的情况下替换现有表。如果存在差异,请确保在同步之前进行必要的数据结构修改。

我发现在处理可管理的数据库大小时,使用这种方法通常比找出迁移的问题链更快。

【讨论】:

Hayden,我过去做过类似的步骤,但我不确定它会如何影响另一台计算机。例如,今天的问题是在笔记本电脑上。因此,如果我按照上述在笔记本电脑上清除迁移并创建新的迁移,然后在笔记本电脑上做一些工作,然后推送到 git repo。当我从 git repo 下拉到 Tower 时,我是否会在迁移时遇到同样的问题,因为它们与以前没有太大的不同?迁移目录在 git 中。 第二个问题。由于我只是将一个工作应用程序推送到 git,使用当前的 mysql 备份,当我从 git 和相应的 mysql 备份中拉下代码库时,我真的需要担心模型和数据库吗?我想我可以只恢复数据库备份并用来自 git 的新东西替换现有的代码库,它应该都可以工作。我错过了什么吗? 由于我经常遇到你描述的问题,我倾向于不将迁移文件提交到 git,而是在我同步到的任何计算机上根据需要运行迁移,从而在每个计算机上创建迁移彼此不同的文件夹。我发现这通常会减少 git 和 Django 让自己陷入的困惑。 回答您的问题:您不必担心,我只是谨慎! @Hayden Eastwood 提交迁移文件被鼓励并在 Django 文档中被提及为最佳实践,请参阅这篇文章 ***.com/a/28035246/12893650。我一直在从事几个 Django 项目。我和其他开发人员提交迁移到 git 的所有项目都顺利进行,唯一导致此处描述的相同问题的项目是我们忽略了迁移并使用 SQL 转储的项目。【参考方案2】:

您是否尝试在笔记本电脑上进行迁移? 这会将迁移标记为已应用,这样您就不会再遇到麻烦了。

伪造单个迁移文件: python manage.py migrate --fake &lt;APP_NAME&gt; &lt;MIGRATION&gt;

伪造应用的所有迁移: python manage.py migrate --fake &lt;APP_NAME&gt;

伪造所有迁移: python manage.py migrate --fake

【讨论】:

首先,我不确定你的问题是什么意思。我目前的情况是,将工作应用程序上传到 git,并从 tower 进行相应的 mysql 备份。我从 git 下载了工作应用程序和从 git 到笔记本电脑的 mysql 备份,它覆盖了笔记本电脑上的旧代码和笔记本电脑上的旧数据库。笔记本电脑和塔现在应该是相同的,除了在笔记本电脑上迁移失败而不是在塔上。其次,在这种情况下,伪造迁移将如何提供帮助? 好的,问题没有解决。您能以某种方式验证您笔记本电脑上的数据库与塔上的数据库相同吗?由于 Django 将有关迁移的信息存储在数据库中,因此应该没有任何区别。无论如何,使用虚假迁移,您可以让 Django 假装它迁移了迁移,而无需实际运行迁移。当我说对时,您的应用程序正在运行,一切似乎都很好。如果是这样,您可以尝试虚假迁移;)

以上是关于利用gitrepo无缝迁移git项目的主要内容,如果未能解决你的问题,请参考以下文章

Django 迁移失败

一种方法hg同步git

git subtree:无缝管理通用子项目

在工作 dbt 项目中调用 packages.yml 中的 git repo

如何克隆 git 裸仓库并更改分支名称

Git项目迁移-保留分支和提交记录