如何在保留历史记录的同时拆分并重命名 git 中的代码文件?

How to split out and rename code files in git while preserving history?

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

  1. 需要将标题不太理想的 REPO 和一些子文件夹和文件重命名为干净的 python 标准符号(从使用破折号到带下划线等的短名称)。

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

我发现在 git 中清理上述代码和文件结构很难保存更改历史记录。关于该主题的其他答案似乎涵盖了这项工作的一部分。我尝试通过 git 在线重命名文件,但是,虽然正式保留了历史记录,但它仅存储已移至 \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 有提交,提交 历史。每个提交都有 每个 文件的完整快照。1

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

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

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

这基本上就是您得到的全部。那么,在重命名文件或重构项目时,最好的办法是提交 重命名,作为一次提交,然后提交任何其他所需的更改。您 没有 这样做,因为重命名检测器通常可以将重命名的 and-changed 文件检测为已重命名,但是您得到当您单独提交重命名时,更好的 rename-detection 保证,以便每个文件与前一个文件 100% 匹配。

请注意,是否打开任何特定的 GUI rename-detection,如果打开,如何打开,取决于该 GUI。 Git 提供的都是提交。


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

但是,这也意味着当您使用 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