【问题标题】:How to split out and rename code files in git while preserving history?如何在保留历史记录的同时拆分和重命名 git 中的代码文件?
【发布时间】:2021-01-13 06:05:56
【问题描述】:

我是 git 新手,在决定清理代码结构后,我现在面临 git repo 'housekeeping' 挑战。我的挑战有两个方面:

  1. 需要将标题欠佳的 REPO 以及一些 SUBFOLDERS 和 FILES 重命名为干净的 Python 标准符号(从使用破折号到带有下划线的较短名称等)。

  2. 将测试代码拆分为保存在专用 \tests 文件夹中的 .py 文件。

我发现在 git 中清理上述代码和文件结构很难保留更改历史记录。关于该主题的其他答案似乎涵盖了这项工作的一部分。我尝试通过 git online 重命名文件,但是,虽然历史记录被正式保留,但它只存储已移动到 \test 文件夹的大量测试代码的批量删除行为。新创建的 \tests\basic_test.py 和 \tests\advanced_test.py 文件显然被 git 视为新文件,即之前的更改历史为零。

简而言之,我需要将测试代码拆分为存储在新的 \tests 子文件夹中的新文件,然后通过重命名 repo 来重命名根代码文件夹。 这可能吗不使用 git 命令行完成?如果不是,我想现在是我学习它的时候了,我很欣赏指导来实现我在上面跳入水中所需的内容,但不会在 git 命令行教程中陷入困境,即以最少的理论获取影响我需要的改变。

非常感谢分享智慧!

- mt code structure 1.0

\money-tracker # local dir and git repo name    
  money_tracker_v01_9.4


- mt code structure 2.0

\money_tracker # app root_dir (local dir and git repo name)
  \mt # code_dir (shared code base named after main mod)
   mt.py

  \tests
   test_basic.py
   test_advanced.py

   \data_in (private, local)
    coa.csv
    trxn_data_x.csv

   \data_out (private, local)
    cf_report_x.txt

* each mt_dir may contain aux files (f.e. __init__.py, context.py)

【问题讨论】:

    标签: git git-rewrite-history code-structure


    【解决方案1】:

    您必须学习的最低理论部分是:Git 没有 文件历史记录。 Git 有提交,而提交历史。每个提交都有每个文件的完整快照。1

    Git 可以随时比较任何两个现有的提交。如果旧提交中有一个名为 F 的文件,而新提交中有一个名为 F 的文件,我们一般假设这是同一个文件时间>。但是假设旧提交有一个名为 old/path/to/name1.py 的文件,而新提交有一个名为 new/name/of/name2.py 的文件。2 那么也许这些应该被认为是“同一个文件”,即使它们有不同的名字。

    如果某个提交重命名了某个文件,Git 可以尝试检测该重命名。此重命名检测取决于文件在内容方面是否足够相似。内容的 100% 匹配保证了 Git 可以很容易地找到重命名。所以当你有一个提交时只是重命名文件,告诉 Git 告诉我在这个提交中发生了什么变化,顺便说一下,在你这样做的时候检测重命名 3 将使 Git 将“之前”快照与“之后”进行比较,它会找到所有重命名。

    为了向您显示带有git log --follow -- <em>path</em> 的假装“文件历史记录”,Git 只需查看每个提交。 Git 从最后开始并向后工作(它总是这样做),比较前后快照,启用重命名检测。如果 path 在“之后”提交中,并且 Git 发现它是从“之前”提交中的某个 previous 路径重命名的,Git 会告诉你这一点,并且然后开始寻找旧的路径名。

    这基本上就是你所得到的。那么,在重命名文件或重组项目时,最好的办法是提交 just 重命名,作为一次提交,然后提交所需的任何其他更改。您没有必须执行此操作,因为重命名检测器通常可以检测重命名的-和-更改文件已重命名,但是当您分别提交重命名,以便每个文件 100% 匹配前一个。

    请注意,任何特定的 GUI 是否启用重命名检测,如果启用,如何启用,取决于该 GUI。 Git 提供的所有内容都是提交。


    1提交中的文件以一种特殊的、只读的、仅限 Git 的、压缩和去重的格式存储。这意味着,如果您连续进行一千次提交,并且只更改一次README.md,那么您将拥有旧版本的 998 个共享副本和新版本的 2 个共享副本,或者旧版本的 400 个共享副本和新副本的 600 个共享副本,因此无论哪种方式,它实际上只是 in 存储库两次,而不是一千次。

    然而,这也意味着当您使用 Git 存储库时,您看到和处理的文件不在 Git 存储库中。您看到和使用的文件是从存储库中提取的副本,并在此过程中转回可用文件。这很好地解释了 Git 的行为方式。

    2请注意,斜杠(尽管您可以在 Windows 上使用反斜杠)是每个文件名的一部分:例如,名称是 old/path/to/name1.py。那不是一个名为old 的文件夹包含一个名为path 的文件夹等等,那只是一个名为old/path/to/name1.py 的文件。

    3在命令行中,使用git diff --find-renamesgit show --find-renames 启用重命名检测器,或将diff.renames 设置为true。在 Git 2.9 及更高版本中,diff.renames 默认设置为true;在早期版本中,默认设置为false

    【讨论】:

    • 谢谢你,托雷克!虽然我没有详细理解你的答案,但我还是硬着头皮在备份本地 repo 目录后通过 Git Bash 进行了更改。我最终使用以下 git 命令集进行了更改:(1) git mv -M (期望这组 diff.rename 为 true); (2) git mv old new (重命名代码文件); (3) git commit -am 'commit msg' (进行本地提交); (4) git push(推送到远程); (5) git status (确认一切都是干净的)。已在远程 git repo(在线)中确认保留旧代码文件上的提交历史记录。再次感谢!
    • git mv 没有-M,但这并不重要。要将 diff.renames 设置为 true(如果您使用的是 Git 2.8 或更早版本),请使用 git config。如果您的 Git 版本是 2.9 或更高版本,则默认已设置为 true
    • 再次感谢托雷克。这是一个错字——我的意思是通过运行git diff -M 来设置 diff.renames。这能完成工作吗?为了以防万一,我还在配置中添加了[diff] renames = true。如何检查 diff.renames 是否设置为 true(生效)?
    • git config --get diff.renames 会告诉你它明确设置的内容(对于这个特定的存储库)。如果这没有显示任何内容,则它没有设置并且您获得默认值:git --version 将告诉您您正在使用哪个版本的 Git,以及默认值是什么。无论如何,我都喜欢在全局范围内设置我的,即使我不希望将来使用 2.9 之前的 Git,git config --global diff.renames true
    • 另一种判断方法是区分其中某个文件被重命名的一对提交,当然,看看 Git 是否将其报告为重命名。 :-)
    猜你喜欢
    • 2011-04-22
    • 1970-01-01
    • 2015-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多