代码之家  ›  专栏  ›  技术社区  ›  Greg K

在Git中处理文件重命名

  •  401
  • Greg K  · 技术社区  · 16 年前

    我读到的时候 renaming files in git ,您应该提交任何更改,执行重命名,然后准备重命名的文件。Git将从内容中识别该文件,而不是将其视为新的未跟踪文件,并保留更改历史记录。

    但是,今晚我就这么做了,结果我又回到了 git mv .

    > $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   modified:   index.html
    #
    

    在查找器中重命名样式表 iphone.css mobile.css

    > $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   modified:   index.html
    #
    # Changed but not updated:
    #   (use "git add/rm <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #   deleted:    css/iphone.css
    #
    # Untracked files:
    #   (use "git add <file>..." to include in what will be committed)
    #
    #   css/mobile.css
    

    所以Git现在认为我已经删除了一个CSS文件,并添加了一个新的。不是我想要的,让我们撤消重命名,让Git来做这项工作。

    > $ git reset HEAD .
    Unstaged changes after reset:
    M   css/iphone.css
    M   index.html
    

    回到我开始的地方。

    >$git状态
    #在分支主机上
    #要提交的更改:
    #(使用“git reset head<file>…”取消固定)
    γ
    #修改:index.html
    γ
    

    让我们使用 重命名 相反。

    > $ git mv css/iphone.css css/mobile.css
    > $ git status
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   renamed:    css/iphone.css -> css/mobile.css
    #
    # Changed but not updated:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #   modified:   index.html
    #
    

    看来我们很好。那么为什么我第一次使用finder时Git没有识别出这个名字呢?

    11 回复  |  直到 8 年前
        1
  •  323
  •   vsync    11 年前

    为了 git mv 这个 manual page

    索引在成功完成后更新, [……]

    所以,首先你必须自己更新索引 (通过使用 git add mobile.css )然而
    git status 仍将显示两个不同的文件

    $ git status
    # On branch master
    warning: LF will be replaced by CRLF in index.html
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   index.html
    #       new file:   mobile.css
    #
    # Changed but not updated:
    #   (use "git add/rm <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #       deleted:    iphone.css
    #
    

    您可以通过运行获得不同的输出 git commit --dry-run -a 结果就是你 期待

    Tanascius@H181 /d/temp/blo (master)
    $ git commit --dry-run -a
    # On branch master
    warning: LF will be replaced by CRLF in index.html
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #       modified:   index.html
    #       renamed:    iphone.css -> mobile.css
    #
    

    我不能确切地告诉你为什么我们看到这些差异 之间 Git状态
    git commit--试运行-a 但是 这里有一个提示 Linus

    Git真的没有 照顾 关于整体 内部的“重命名检测”,以及您拥有的所有提交 用重命名完成完全独立于 我们用启发式方法 显示 重命名。

    dry-run 使用真正的重命名机制,而 Git状态 可能不会。

        2
  •  72
  •   Community Mohan Dere    9 年前

    在Git将其识别为移动文件之前,必须将两个修改过的文件添加到索引中。

    唯一的区别是 mv old new git mv old new 是指git mv还将文件添加到索引中。

    mv旧的新的 然后 git add -A 也会起作用的。

    注意,你不能只使用 git add . 因为这不会向索引中添加删除操作。

    Difference between "git add -A" and "git add ."

        3
  •  18
  •   dimuthu    11 年前

    最好是自己试试。

    mkdir test
    cd test
    git init
    touch aaa.txt
    git add .
    git commit -a -m "New file"
    mv aaa.txt bbb.txt
    git add .
    git status
    git commit --dry-run -a
    

    现在git status和git commit--dry run-a显示两个不同的结果,其中git status显示bbb.txt作为新文件/aaa.txt被删除,而--dry run命令显示实际重命名。

    ~/test$ git status
    
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   new file:   bbb.txt
    #
    # Changes not staged for commit:
    #   (use "git add/rm <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #   deleted:    aaa.txt
    #
    
    
    /test$ git commit --dry-run -a
    
    # On branch master
    # Changes to be committed:
    #   (use "git reset HEAD <file>..." to unstage)
    #
    #   renamed:    aaa.txt -> bbb.txt
    #
    

    现在去办理登机手续。

    git commit -a -m "Rename"
    

    现在,您可以看到文件实际上被重命名了,Git状态中显示的内容是错误的。

    这个故事的寓意是:如果你不确定你的文件是否被重命名,那么就发布一个“git-commit-dry-run-a”。如果它显示文件已重命名,则可以继续。

        4
  •  10
  •   knittl    16 年前

    你必须 git add css/mobile.css 新文件和 git rm css/iphone.css 所以Git知道。然后它将显示相同的输出 git status

    您可以在状态输出(文件的新名称)中清楚地看到它:

    # Untracked files:
    #   (use "git add <file>..." to include in what will be committed)
    

    和(旧名称):

    # Changed but not updated:
    #   (use "git add/rm <file>..." to update what will be committed)
    

    我想在幕后 git mv 只不过是一个包装脚本,它可以做到这一点:从索引中删除文件并用其他名称添加它

        5
  •  9
  •   albfan    11 年前

    让我们从Git的角度来考虑您的文件。

    请记住,Git不会跟踪有关文件的任何元数据

    您的存储库中有

    $ cd repo
    $ ls
    ...
    iphone.css
    ...
    

    受Git控制:

    $ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked
    file is tracked
    

    测试方法:

    $ touch newfile
    $ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked
    (no output, it is not tracked)
    $ rm newfile
    

    当你这样做的时候

    $ mv iphone.css mobile.css
    

    从Git的角度来看,

    • 没有 iPhone.css(英文) (已删除-Git警告-)。
    • 有一个新文件 手机.css .
    • 这些文件完全无关。

    所以,Git建议使用它已经知道的文件( iPhone.css(英文) )以及它检测到的新文件( 手机.css )但只有当文件在index或head git中时,才会开始检查其内容。

    此时,“iphone.css删除”和 手机.css 在索引上。

    将iphone.css删除添加到索引

    $ git rm iphone.css
    

    吉特告诉你到底发生了什么:( iPhone.css(英文) 已删除。什么都没发生)

    然后添加新文件 手机.css

    $ git add mobile.css
    

    这一次,删除和新文件都在索引中。现在Git检测到上下文是相同的,并将其公开为重命名。事实上,如果文件有50%的相似性,它会检测到这是一个重命名,它允许您更改 手机.css 将操作保留为重命名时。

    看这是可复制的 git diff . 既然您的文件在索引上,您必须使用 --cached . 编辑 手机.css 一点,将其添加到索引中,并查看以下内容之间的区别:

    $ git diff --cached 
    

    $ git diff --cached -M
    

    -M “检测重命名”选项是否用于 差异比较 . -m 代表 -M50% (50%或更多的相似性将使git将其表示为重命名),但您可以将其减少到 -M20% (20%)如果你经常编辑mobile.css。

        6
  •  8
  •   GrigorisG    10 年前

    对于git 1.7.x,以下命令适用于我:

    git mv css/iphone.css css/mobile.css
    git commit -m 'Rename folder.' 
    

    不需要git-add,因为原来的文件(即css/mobile.css)已经在以前提交的文件中了。

        7
  •  7
  •   hasen    16 年前

    Git将从内容中识别该文件,而不是将其视为新的未跟踪文件。

    这就是你出错的地方。

    只是 之后 你添加文件,Git会从内容中识别它。

        8
  •  7
  •   Haimei    12 年前

    步骤1:将文件从oldfile重命名为newfile

    git mv #oldfile #newfile
    

    步骤2:git提交并添加注释

    git commit -m "rename oldfile to newfile"
    

    第3步:将此更改推送到远程服务器

    git push origin #localbranch:#remotebranch
    
        9
  •  3
  •   Mike Seplowitz    16 年前

    你没有准备好你的搜寻者行动的结果。我相信如果你通过查找器移动然后 git add css/mobile.css ; git rm css/iphone.css ,git将计算新文件的散列值,然后才意识到文件的散列值匹配(因此这是一个重命名)。

        10
  •  2
  •   pckben    14 年前

    如果您真的需要手动重命名文件,例如使用脚本批量重命名一组文件,然后使用 git add -A . 为我工作。

        11
  •  1
  •   doozMen    13 年前

    对于Xcode用户:如果在Xcode中重命名文件,则会看到徽章图标更改为追加。如果您使用Xcode进行提交,那么实际上会创建一个新文件并丢失历史记录。

    解决方法很简单,但在使用Xcode提交之前必须先完成:

    1. 对文件夹执行Git状态。您应该看到阶段性更改是正确的:

    已重命名:project/oldname.h->project/newname.h 已重命名:project/oldname.m->project/newname.m

    1. do commit-m“名称更改”

    然后返回到Xcode,您将看到徽章从A更改为M,现在保存它以在使用Xcode时提交进一步的更改。

    推荐文章