在git中处理文件重命名

我读过,当在git中重命名文件 ,你应该提交任何更改,执行重命名,然后阶段重命名的文件。 Git会从内容中识别文件,而不是将其视为新的未跟踪文件,并保留更改历史logging。

然而,今晚我做了这个,最后我还是回到了git mv

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

在Finder mobile.css我的样式表从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 status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # modified: index.html # 

让我们改用git mv

 > $ 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没有认识到重命名?

对于手册页说git mv

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

所以,首先你必须自己更新索引(通过使用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 status
git commit --dry-run -a ,但这里是来自Linus的提示

git实际上并不关心内部的整个“重命名检测”,任何你用重命名完成的提交都完全独立于我们用来显示重命名的启发式。

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

你必须将两个修改后的文件添加到索引,然后git会将其识别为一个移动。

mv old newgit mv old new的唯一区别就是git mv也会将这些文件添加到索引中。

mv old new然后git add -A也会工作。

请注意,你不能只使用git add . 因为这不会增加清除指标。

查看“git add -A”和“git add”之间的区别。

最好的事情是自己尝试。

 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状态和git commit –dry-run -a显示两个不同的结果,其中git状态显示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”。 如果它显示文件被重命名,那么你很好。

你必须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只不过是一个包装脚本,它正是这样做的:从索引中删除文件,并以不同的名称添加它

第一步:将文件从旧文件重命名为新文件

 git mv #oldfile #newfile 

第二步:git提交并添加注释

 git commit -m "rename oldfile to newfile" 

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

 git push origin #localbranch:#remotebranch 

让我们从git的angular度来思考你的文件。

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

您的存储库(除其他外)

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

它是在git控制下:

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

testing这个:

 $ 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的angular度来看,

  • 没有iphone.css (它被删除 – git警告关于 – )。
  • 有一个新的文件mobile.css
  • 这些文件是完全不相关的。

所以,gitbuild议它已经知道的文件( iphone.css )和它检测到的新文件( mobile.css ),但只有当文件在索引或HEAD git开始检查他们的内容。

此时,“iphone.css删除”和mobile.css都不在索引上。

将iphone.css删除添加到索引

 $ git rm iphone.css 

git告诉你到底发生了什么:( iphone.css被删除,没有更多的事情发生)

然后添加新的文件mobile.css

 $ git add mobile.css 

这次删除和新文件都在索引上。 现在git检测上下文是相同的,并将其公开为重命名。 事实上,如果文件是50%的相似,它会检测到作为重命名,可以让您更改mobile.css一点,同时保持作为重命名的操作。

看到这是可重复的git diff 。 现在你的文件在索引上,你必须使用--cached 。 编辑mobile.css一下,加上索引,看看区别:

 $ git diff --cached 

 $ git diff --cached -M 

-Mgit diff的“检测重命名”选项。 -M代表-M50% (50%或更多的相似性会使git表示为重命名),但是如果你编辑mobile.css的话,你可以把它降低到-M20% (20%)。

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

那是你出错的地方。

只有添加文件后,git才会从内容中识别出来。

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

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

没有必要添加git,因为原来的文件(即css / mobile.css)已经在提交的文件中。

你没有find你的发现者的结果。 我相信如果你通过Finder做了这个动作,然后做了git add css/mobile.css ; git rm css/iphone.css git add css/mobile.css ; git rm css/iphone.css ,git会计算新文件的散列,然后才会意识到这些文件的散列匹配(因此是重命名)。

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

对于Xcode用户:如果您在Xcode中重命名文件,则会看到徽章图标更改为附加。 如果您使用XCode进行提交,您将实际创build一个新文件并丢失历史logging。

解决方法很简单,但您必须在使用Xcode之前完成此操作:

  1. 在你的文件夹上做一个git状态。 你应该看到阶段性变化是正确的:

改名为:Project / OldName.h – > Project / NewName.h改名为:Project / OldName.m – > Project / NewName.m

  1. 做提交-m'名称改变'

然后返回到XCode,您将看到从A更改为M的徽章,现在可以保存更多的使用xcode的更改。

Interesting Posts