如何将 __init__.py 中 git 中的内容(并保留历史记录)传输到另一个文件,同时仍保持空 __init__.py
How to transfer contents from __init__.py in git (and maintain history) to another file whilst still keeping empty __init__.py
我创建了一个从 __init__.py 导入的导入方案,而不是 __init__.py 从它的模块导入。
为了解决这个问题,我 运行:
$ git mv package/__init__.py package/utils.py
这看起来是正确的:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: package/__init__.py -> package/utils.py
但是,如果我 运行 以下内容:
$ touch package/__init__.py
这是我看到的:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: package/__init__.py
new file: package/utils.py
我怎样才能 git 执行以下操作?
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: package/utils.py
new file: package/__init__.py
TL;DR
如果您愿意,可以进行两次提交。这没有太多价值,但也有一点。它的一些值是正的,一些是负的。这是你的选择。
长
Git 没有文件历史记录。 Git 已提交;提交 是 历史。
提交本身相对简单:每个提交都有每个文件的完整快照,加上一些元数据,其中包含提交作者的姓名和电子邮件地址等内容。任何一次提交的元数据包括任何早期提交的原始哈希 ID。大多数提交,称为 ordinary 提交,有一个较早的提交,并且那个较早的提交也有一个快照和元数据,它指向另一个更早的提交,等等。这就是快照和元数据是历史的方式。
考虑到这一点,请注意 git log -p
或 git show
显示 普通提交:
- 显示其元数据(有趣的部分),带格式;然后
- 显示该提交中更改的内容。
为了实现第2项,Git实际上是将提交及其父都提取到一个临时区域(内存中),然后比较两组快照文件的数量。1 此比较采用 diff (git diff
) 的形式,即两个快照之间的差异。
git status
命令也运行 git diff
。事实上,它运行 git diff
两次 ,一次是为了比较当前(又名 HEAD
)提交与 Git 的索引——你提议的下一次提交,由任何 git add
更新产生——并再次将 Git 的索引与您的工作树进行比较,以防您忘记 git add
。 (这种 diff 形式至少使用了一个未保存在提交中的快照,并且两种形式之一使用真实文件,这比使用 Git 的快捷哈希 ID 技巧需要更多的工作。但最终结果是一样。)
当 Git 运行这种差异时,它可以——现在,默认情况下——查找 重命名的 文件。但是,它查找这些重命名的方法并不完善。它的作用是这样的:
- 列出左侧的所有文件(“之前”或“旧版本”)。
- 列出右侧的所有文件(“之后”或“新版本”)。
- 如果左右有一对文件具有相同的名称,将它们配对:它们必须相同文件.
- 取所有剩下的、未配对的名字。其中一些可能是 重命名 。对照所有右侧文件检查所有左侧文件。2 如果左侧文件与右侧文件“足够相似”,则将最佳匹配配对。 (在大多数情况下,100% 相同的匹配在这里进行得更快,并减少剩余的未配对名称堆,所以 Git 总是先这样做。)
当你 运行:
git mv package/__init__.py package/utils.py
设置非常适合 Git:每个 other 文件左右匹配 100%,剩下的列表是左侧有 __init__.py
右侧有 utils.py
并且内容匹配 100%。所以那一定是重命名! (在某种程度上,这些文件被命名为 package/__init__.py
等:Git 将包括斜杠在内的整个文件视为一个文件名。但对我来说,省去 package/
,您可能自己将这些视为文件夹中的文件或目录中的文件。)
但是,一旦您创建了一个名为 __init__.py
的新文件,Git 现在就同时拥有了名为 __init__.py
的左侧和右侧文件,加上这个剩余的右侧文件命名为 utils.py
。因此 Git 将具有 相同 名称的文件配对,并留下一个无法配对的右侧文件。
如果您现在进行新的提交,在这种情况下,git diff
将继续查找以这种方式设置的内容,至少直到某个神秘的未来 Git 足够聪明地注意到,即使这两个文件具有相同的 名称,一个表示“重命名然后重新创建”的差异在某种程度上更优越。3
但是,如果您进行的提交仅包含 重命名步骤 ,然后创建一个新的 __init__.py
文件以便包正常工作并提交作为 second 提交,git log -p
和 git show
将恢复检测重命名。这样做的好处是 git log --follow
会在检测到重命名时通过 更改它正在寻找的名称 逐步进行工作。这样做的缺点是您将有一个提交被故意破坏。您可能应该在其提交消息中注意到这一点。如果您必须经常做这种事情,并且提交消息始终标记此类提交,您可以在 git bisect
期间自动跳过此类提交,方法是编写 bisect 脚本测试程序来检查这些标记。
1从技术上讲,Git 只比较树和 blob 的哈希 ID,这使得在大多数情况下速度非常快。
2这个检查在计算上非常昂贵,所以 Git 有很多捷径,还有一个它只是放弃的截止限制。您可以调整其中一些设置。
3要是以后的git diff
就是这么聪明,以后的Git作者就得考虑了这是否会破坏一些脚本。幸运的是 git diff
是瓷器命令,而不是管道命令,但是 git diff-tree
和其他管道命令将需要新选项。
我创建了一个从 __init__.py 导入的导入方案,而不是 __init__.py 从它的模块导入。
为了解决这个问题,我 运行:
$ git mv package/__init__.py package/utils.py
这看起来是正确的:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
renamed: package/__init__.py -> package/utils.py
但是,如果我 运行 以下内容:
$ touch package/__init__.py
这是我看到的:
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: package/__init__.py
new file: package/utils.py
我怎样才能 git 执行以下操作?
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: package/utils.py
new file: package/__init__.py
TL;DR
如果您愿意,可以进行两次提交。这没有太多价值,但也有一点。它的一些值是正的,一些是负的。这是你的选择。
长
Git 没有文件历史记录。 Git 已提交;提交 是 历史。
提交本身相对简单:每个提交都有每个文件的完整快照,加上一些元数据,其中包含提交作者的姓名和电子邮件地址等内容。任何一次提交的元数据包括任何早期提交的原始哈希 ID。大多数提交,称为 ordinary 提交,有一个较早的提交,并且那个较早的提交也有一个快照和元数据,它指向另一个更早的提交,等等。这就是快照和元数据是历史的方式。
考虑到这一点,请注意 git log -p
或 git show
显示 普通提交:
- 显示其元数据(有趣的部分),带格式;然后
- 显示该提交中更改的内容。
为了实现第2项,Git实际上是将提交及其父都提取到一个临时区域(内存中),然后比较两组快照文件的数量。1 此比较采用 diff (git diff
) 的形式,即两个快照之间的差异。
git status
命令也运行 git diff
。事实上,它运行 git diff
两次 ,一次是为了比较当前(又名 HEAD
)提交与 Git 的索引——你提议的下一次提交,由任何 git add
更新产生——并再次将 Git 的索引与您的工作树进行比较,以防您忘记 git add
。 (这种 diff 形式至少使用了一个未保存在提交中的快照,并且两种形式之一使用真实文件,这比使用 Git 的快捷哈希 ID 技巧需要更多的工作。但最终结果是一样。)
当 Git 运行这种差异时,它可以——现在,默认情况下——查找 重命名的 文件。但是,它查找这些重命名的方法并不完善。它的作用是这样的:
- 列出左侧的所有文件(“之前”或“旧版本”)。
- 列出右侧的所有文件(“之后”或“新版本”)。
- 如果左右有一对文件具有相同的名称,将它们配对:它们必须相同文件.
- 取所有剩下的、未配对的名字。其中一些可能是 重命名 。对照所有右侧文件检查所有左侧文件。2 如果左侧文件与右侧文件“足够相似”,则将最佳匹配配对。 (在大多数情况下,100% 相同的匹配在这里进行得更快,并减少剩余的未配对名称堆,所以 Git 总是先这样做。)
当你 运行:
git mv package/__init__.py package/utils.py
设置非常适合 Git:每个 other 文件左右匹配 100%,剩下的列表是左侧有 __init__.py
右侧有 utils.py
并且内容匹配 100%。所以那一定是重命名! (在某种程度上,这些文件被命名为 package/__init__.py
等:Git 将包括斜杠在内的整个文件视为一个文件名。但对我来说,省去 package/
,您可能自己将这些视为文件夹中的文件或目录中的文件。)
但是,一旦您创建了一个名为 __init__.py
的新文件,Git 现在就同时拥有了名为 __init__.py
的左侧和右侧文件,加上这个剩余的右侧文件命名为 utils.py
。因此 Git 将具有 相同 名称的文件配对,并留下一个无法配对的右侧文件。
如果您现在进行新的提交,在这种情况下,git diff
将继续查找以这种方式设置的内容,至少直到某个神秘的未来 Git 足够聪明地注意到,即使这两个文件具有相同的 名称,一个表示“重命名然后重新创建”的差异在某种程度上更优越。3
但是,如果您进行的提交仅包含 重命名步骤 ,然后创建一个新的 __init__.py
文件以便包正常工作并提交作为 second 提交,git log -p
和 git show
将恢复检测重命名。这样做的好处是 git log --follow
会在检测到重命名时通过 更改它正在寻找的名称 逐步进行工作。这样做的缺点是您将有一个提交被故意破坏。您可能应该在其提交消息中注意到这一点。如果您必须经常做这种事情,并且提交消息始终标记此类提交,您可以在 git bisect
期间自动跳过此类提交,方法是编写 bisect 脚本测试程序来检查这些标记。
1从技术上讲,Git 只比较树和 blob 的哈希 ID,这使得在大多数情况下速度非常快。
2这个检查在计算上非常昂贵,所以 Git 有很多捷径,还有一个它只是放弃的截止限制。您可以调整其中一些设置。
3要是以后的git diff
就是这么聪明,以后的Git作者就得考虑了这是否会破坏一些脚本。幸运的是 git diff
是瓷器命令,而不是管道命令,但是 git diff-tree
和其他管道命令将需要新选项。