Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Git 将删除和添加文件的两次提交转换为文件移动的一次提交_Git_Rebase - Fatal编程技术网

Git 将删除和添加文件的两次提交转换为文件移动的一次提交

Git 将删除和添加文件的两次提交转换为文件移动的一次提交,git,rebase,Git,Rebase,我用Subgit导入了SVN存储库,但在git方面遇到了问题。 每个源文件最早的版本是2014年的版本,尽管该项目始于2008年 这是由从Ant切换到Maven(它是Java项目)引起的,它将源目录结构从/src/package/更改为/src/main/Java/package。通过svn log我可以看到有两次这样的革命: 在第一个示例中,删除了所有源代码 在第二个示例中,源文件被添加为遵循Maven目录结构 这就是为什么git只能显示Ant->Maven迁移当天的最早版本 我能否以某种

我用Subgit导入了SVN存储库,但在git方面遇到了问题。 每个源文件最早的版本是2014年的版本,尽管该项目始于2008年

这是由从Ant切换到Maven(它是Java项目)引起的,它将源目录结构从
/src/package/
更改为
/src/main/Java/package
。通过
svn log
我可以看到有两次这样的革命:

  • 在第一个示例中,删除了所有源代码
  • 在第二个示例中,源文件被添加为遵循Maven目录结构
这就是为什么
git
只能显示Ant->Maven迁移当天的最早版本


我能否以某种方式重写git历史记录,使git了解所有文件实际上都已移动,但未删除并重新添加?

使用
git筛选器分支
删除删除所有源文件的提交:

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = insert_SHA1_to_remove_here ];
    then
            skip_commit "$@";
    else
            git commit-tree "$@";
    fi' --tag-name-filter cat --all

有关更多详细信息,请参阅(搜索“Darl”)。

使用
git过滤器分支
删除删除所有源文件的提交:

git filter-branch --commit-filter '
    if [ "$GIT_COMMIT" = insert_SHA1_to_remove_here ];
    then
            skip_commit "$@";
    else
            git commit-tree "$@";
    fi' --tag-name-filter cat --all
有关更多详细信息,请参阅(搜索“Darl”)。

您有三个选项 就Git而言,不存在使用文件移动进行提交的情况。提交只是一个快照:“这就是所包含的内容。”就是这样:不多也不少。在其他VCSE中,旧提交a之后的新提交B不仅仅是“what's In”的快照,它也是“what's changed”,可能包括“重命名的路径/到/文件到不同的/路径/到/新名称”之类的内容。然而,Git却选择(尝试)在稍后,通过比较commit B的新内容和commit A的旧内容,来重构您在查看它时所更改的内容

一般来说,Git一次后退一次提交:比较Y和Z,然后比较X和Y,然后比较W和X,依此类推。例如,
git日志
git日志
就是这样做的。注意,我在这里给出了提交的单字母名称,并假设了一个线性序列:
a--B--C--Z
。实际上,我们需要更长的ID,并且不是所有的序列都是线性的(但幸运的是,这个问题附近的序列都是线性的)

这对您意味着,您必须说服Git不要将commit H(“commit that,vs G,有新名称下的文件”)与commit G(“commit that,当与F比较时,删除旧名称下的文件”)进行比较,而是将commit H与commit F进行比较,跳过G。事实上,也许我们也想通过比较commit I来跳过commit H(H之后的一个)提交F(G之前的一个)。这比跳过已删除文件的提交更重要

对于所有选项,我们需要知道(或找到)几个Git的提交ID。四个“特别有趣”的提交是:

  • “再次添加所有文件”的提交:上面是H,但我们称之为
    adda
    (实际上是一个潜在有效的Git哈希ID)。您需要找到真实的ID
  • “删除所有文件”的提交。这是上面的父项,因此我们可以使用Git提供的有趣的后缀hat(
    ^
    )语法命名它,方法是编写
    addadda^
    。但我们只需假设原始编号为
    de7ede1e7ede1e7ede1e7ede1e7ede1e7ede1e
  • 我们可能还需要知道
    adda
    之后的提交。这就是我们称之为“I”的提交上图:由于Git反向遍历历史,commit
    GoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGoodGood
  • 在所有删除之前提交。同样,我们可以使用hat语法,事实上,知道“好”提交ID,我们可以只使用
    goodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgoodgo
选项1:只需告诉
git bull
跳过提交 有几种方法可以做到这一点,但有一种方法在其他Git命令中无法直接使用:

-S
使用revs文件中的修订,而不是调用

此选项的文档很差(在我看来):
-S
文件参数不是修订列表,而是移植列表

这意味着,您可以运行以下命令,而不是
git dull

echo addaddaddaddaddaddaddaddaddaddaddaddadda \
  $(git rev-parse de1e7ede1e7ede1e7ede1e7ede1e7ede1e7ede1e^) > \
  /tmp/graft
git blame -S /tmp/graft file-you-are-concerned-with
(或类似,取决于您的操作系统)。有关其他技巧,请参见下文,因为您可能也想跳过“添加”提交。当然,这里的两个原始提交ID必须是正确的

(如果您在“delete”提交之前拥有提交的原始ID,您可以使用它来代替调用
git rev parse
。调用
rev parse
的好处是,您可以使用缩写提交,从而获得完整的提交,当然还有所有常见的git revisions语法。“echo”确保两个ID位于同一行,因为
-S
文件的处理方式与旧的Git grafts hack相同。)

选项2:更一般地隐藏提交 如果要对大多数Git命令隐藏提交,可以使用以下方法在一个存储库中更永久地执行该操作(以不在其他位置传播的方式):

我们在这里所做的是告诉Git,每当它要查看commit
adda
时,它应该将目光转向新的“替换”提交。Git replace
命令主要通过复制
来提交新的替换
git replace --graft goodgoodgoodgoodgoodgoodgoodgoodgoodgood \
    de1e7ede1e7ede1e7ede1e7ede1e7ede1e7ede1e^
             -------I'  <-- replacement for I
            /
A--...--E--F--G--H--I--J--...--Z   <-- HEAD