Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/22.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_Version Control_Git Filter Branch - Fatal编程技术网

使用git筛选器分支更改文件名大小写

使用git筛选器分支更改文件名大小写,git,version-control,git-filter-branch,Git,Version Control,Git Filter Branch,我有一个git repo,其中一些文件的名称仅在不同的分支之间存在大小写差异 作为一个简化的示例,在master中有一个文件alpha/beta/foo.cpp,在branchbar中有一个文件alpha/beta/foo.cpp 问题是,当我尝试切换分支时,git不允许我这样做。有一个错误,我现在手头没有,但它基本上看起来像 对文件alpha/beta/Foo.cpp的更改将被覆盖--正在中止 即使后续的git状态显示工作目录是干净的 由于这个repo尚未共享(它实际上是我正在进行迁移的大型p

我有一个git repo,其中一些文件的名称仅在不同的分支之间存在大小写差异

作为一个简化的示例,在master中有一个文件
alpha/beta/foo.cpp
,在branch
bar
中有一个
文件alpha/beta/foo.cpp

问题是,当我尝试切换分支时,git不允许我这样做。有一个错误,我现在手头没有,但它基本上看起来像

对文件alpha/beta/Foo.cpp的更改将被覆盖--正在中止

即使后续的
git状态显示工作目录是干净的

由于这个repo尚未共享(它实际上是我正在进行迁移的大型performe仓库的镜像),我认为使用
git filter branch
重写历史记录没有问题,但是当我这样做时,我所做的任何区分大小写的更改都会丢失

当我使用

git filter-branch -f -d /tmp/tmpfs/filter-it \
--tree-filter path/to/script \
--tag-name-filter cat --prune-empty -- --all
脚本是这样的

#!/bin/bash
if [ -e alpha/beta/foo.cpp ] ; then
    mv alpha/beta/foo.cpp alpha/beta/Foo.cpp
fi
最终结果是重写了引用(预期),但文件本身并没有像我预期的那样跨两个分支重命名

有什么建议吗?

简短的回答 从多个来源修改了以下解决方案:

  • 下面是一个筛选器分支调用,它使用索引筛选器重写提交,而不使用工作副本,因此它应该运行得非常快。注意,作为一个例子,我将文件
    alpha/beta/foo.cpp
    重命名为
    alpha/beta/foo.cpp

    与任何具有潜在破坏性的Git操作一样,强烈建议您在使用此操作之前对回购进行备份克隆:

    git过滤器分支--索引过滤器'
    git ls文件——阶段|\
    sed“s:alpha/beta/foo.cpp:alpha/beta/foo.cpp:”\
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new\
    git更新索引--索引信息&&\
    mv“$GIT_INDEX_FILE.new”“$GIT_INDEX_FILE”
    ”“头
    
    请注意,
    是可选的,因为它应该是
    过滤器分支
    的默认值。它将重写所有从根提交到头指向的提交的提交。如果您想进一步提高筛选器分支的速度,可以传递一系列提交,而不是
    ,例如

    HEAD~20..HEAD
    
    只重写最后20次提交。范围的开头是排他性的,即它不被重写,只有它的子项是排他性的,而结尾的
    HEAD
    也是可选的,因为它是默认值

    验证 最好做一些快速的健全性检查,以验证过滤器分支是否完成了您期望它完成的任务。首先,将当前历史与以前的历史进行比较:

    git diff --name-status refs/original/refs/heads/master
    D       foo.cpp
    A       Foo.cpp
    
    请注意,当将上一个历史记录与当前历史记录进行比较时,当前历史记录不再具有
    foo.cpp
    (已删除),而
    foo.cpp
    已添加到它

    现在确认
    foo.cpp
    包含与
    foo.cpp
    完全相同的内容:

    git diff refs/original/refs/heads/master:foo.cpp Foo.cpp
    
    输出应该为空,这意味着两个版本之间没有差异

    详细说明 下面的细目也可以在博客文章“”中找到。我在这里总结一下。脚本的基本思想是创建一个新的索引文件,其中包含文件
    foo
    的新名称(即
    foo
    变为
    foo
    ),然后用新索引替换旧索引

    步骤1:获取索引文件内容 首先,当前索引文件内容以某种形式输出,然后使用
    --stage
    选项将其输入到
    git update index

    git ls文件——stage
    100644 195ff081f7d0d37a60181de790ae1c6b9f177be8 0 alpha/beta/foo.cpp
    100644 0504de8997941bf10bcfb5af9a0bf472d6c061d3 0许可证
    100644 6293167f0eb7389b2f6f6b73e838d3a547787cbf 0 README.md
    等
    
    步骤2:重命名文件 由于我们希望将
    foo.cpp
    重命名为
    foo.cpp
    ,因此我们使用带有正则表达式的
    sed
    将字符串
    foo
    替换为
    foo

    "s:alpha/beta/foo.cpp:alpha/beta/Foo.cpp:"
    
    在上面的命令中,我使用冒号
    来分隔
    sed
    命令中的正则表达式,但是您也可以使用其他字符作为分隔符,例如管道
    。我选择了冒号而不是更标准的正斜杠
    /
    作为delimeter,这样就不必转义文件路径中使用的正斜杠

    在管道化
    git ls文件--stage
    sed
    之后,您应该得到以下信息:

    git ls-files --stage | sed "s:alpha/beta/foo.cpp:alpha/beta/Foo.cpp:"
    100644 195ff081f7d0d37a60181de790ae1c6b9f177be8 0       alpha/beta/Foo.cpp
    100644 0504de8997941bf10bcfb5af9a0bf472d6c061d3 0       LICENSE
    100644 6293167f0eb7389b2f6f6b73e838d3a547787cbf 0       README.md
    ...etc...
    
    步骤3:使用重命名的文件创建新索引 现在,
    git ls files--stage
    的修改输出可以通过管道输送到
    git update index--index info
    以重命名索引中的文件。因为我们希望创建一个全新的索引来替换旧索引,所以在调用
    git update index
    命令之前,需要首先设置索引文件路径的一些环境变量:

    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info
    
    步骤4:替换旧索引 现在,我们只需将旧索引替换为新索引,这将有效地“重命名”文件:

    mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    
    总结 下面是整个命令,当所有内容都放在一起时:

    git过滤器分支--索引过滤器'
    git ls文件——阶段|\
    sed“s:alpha/beta/foo.cpp:alpha/beta/foo.cpp:”\
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new\
    git更新索引--索引信息&&\
    mv“$GIT_INDEX_FILE.new”“$GIT_INDEX_FILE”
    ”“头
    
    文档

  • My.profile别名基于@cupcake的答案,修复了如何扩展变量的问题

    用法示例:

    mvidx src/myfile.cs src/myfolder/myfile.cs origin/develop..feature/myfeature

    ~/.profilebash配置文件

    alias mvidx=rewriteIndexToMoveFile
    
    red="\e[0;31m"
    green="\e[0;32m"
    
    rewriteIndexToMoveFile() {
        if [ $# -ne 3 ] ; then        
            echo -e "Rewrite index to move a file in a range of commits."
            echo -e "Args: <from file path> <to file path> <range of commits>"
            echo -e "${green}Examples:"
            echo -e "mvidx src/myproject/myfile.cs src/myproject/subfolder/myfile.cs origin/develop..feature/myfeature"
            return
        fi
    
      fromFilePath=$1
      toFilePath=$2
      revisionRange=$3
    
      echo -e "Renaming ${red}$fromFilePath${nc} to ${red}$toFilePath${nc}."
    
    git filter-branch --index-filter 'git ls-files -s \
        | sed "s|\t'"$fromFilePath"'|\t'"$toFilePath"'|" \
        | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info \
            && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' \
      $revisionRange
    }
    
    alias mvidx=rewriteIndexToMoveFile
    红色=“\e[0;31m”
    绿色=“\e[0;32m”
    重写IndexToMoveFile(){
    如果[$#-ne 3];则
    echo-e“重写索引以将文件移动到