Handling file renames in git
在Git中重命名文件时,应该提交任何更改,执行重命名,然后准备重命名的文件。Git将从内容中识别该文件,而不是将其视为新的未跟踪文件,并保留更改历史记录。
但是,今晚我就这么做了,结果又回到了江户记1(0)。
1 2 3 4 5 6 7 | > $ git status # On branch master # Changes to be committed: # (use"git reset HEAD <file>..." to unstage) # # modified: index.html # |
将finder中的样式表从
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | > $ 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来做这项工作。
1 2 3 4 | > $ git reset HEAD . Unstaged changes after reset: M css/iphone.css M index.html |
回到我开始的地方。
1 2 3 4 5 6 7 | > $ git status # On branch master # Changes to be committed: # (use"git reset HEAD <file>..." to unstage) # # modified: index.html # |
我们用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | > $ 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没有识别出这个名字呢?
对于
The index is updated after successful completion,
[....]
号
所以,首先你必须自己更新索引(使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | $ 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 # |
您可以通过运行获得不同的输出导致你的期待
1 2 3 4 5 6 7 8 9 10 | 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 really doesn't even care about the whole
"rename detection" internally, and any commits you have
done with renames are totally independent of the
heuristics we then use to show the renames.
号
在Git将其识别为移动文件之前,必须将两个修改过的文件添加到索引中。
当时的
请注意,不能只使用
请参见"git add-a"和"git add"之间的区别。
最好是自己试试。
1 2 3 4 5 6 7 8 9 10 | 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命令显示实际重命名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | ~/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 # |
。
现在去办理登机手续。
1 | git commit -a -m"Rename" |
。
现在,您可以看到文件实际上被重命名了,Git状态中显示的内容是错误的。
这个故事的寓意是:如果你不确定你的文件是否被重命名,那么就发布一个"git-commit-dry-run-a"。如果它显示文件已重命名,则可以继续。
对于git 1.7.x,以下命令适用于我:
1 2 | git mv css/iphone.css css/mobile.css git commit -m 'Rename folder.' |
。
不需要git-add,因为原来的文件(即css/mobile.css)已经在以前提交的文件中了。
你必须把新文件和
您可以在状态输出(文件的新名称)中清楚地看到它:
1 2 | # Untracked files: # (use"git add <file>..." to include in what will be committed) |
和(旧名称):
1 2 | # Changed but not updated: # (use"git add/rm <file>..." to update what will be committed) |
号
我认为在幕后,
让我们从Git的角度来考虑您的文件。
Keep in mind git doesn't track any metadata about your files
号
您的存储库中有
1 2 3 4 5 | $ cd repo $ ls ... iphone.css ... |
受Git控制:
1 2 | $ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked file is tracked |
号
测试方法:
1 2 3 4 | $ touch newfile $ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked (no output, it is not tracked) $ rm newfile |
当你这样做的时候
1 | $ mv iphone.css mobile.css |
。
从Git的角度来看,
- 没有iphone.css(已删除-git警告-)。
- 有一个新文件mobile.css。
- 这些文件完全无关。
所以,Git建议使用它已经知道的文件(iphone.css)和它检测到的新文件(mobile.css),但只有当文件在索引中或头Git开始检查它们的内容时。
目前,"iphone.css删除"和mobile.css都不在索引中。
将iphone.css删除添加到索引
1 | $ git rm iphone.css |
Git会告诉你到底发生了什么:(iphone.css被删除。什么都没发生)
然后添加新文件mobile.css
1 | $ git add mobile.css |
。
这一次,删除和新文件都在索引中。现在Git检测到上下文是相同的,并将其公开为重命名。事实上,如果文件有50%的相似性,它会检测到作为一个重命名,这让您在保持操作为重命名的同时稍微更改mobile.css。
请看,这在
1 | $ git diff --cached |
。
和
1 | $ git diff --cached -M |
步骤1:将文件从oldfile重命名为newfile
1 | git mv #oldfile #newfile |
步骤2:git提交并添加注释
1 | git commit -m"rename oldfile to newfile" |
。
第3步:将此更改推送到远程服务器
1 | git push origin #localbranch:#remotebranch |
Git will recognise the file from the contents, rather than seeing it as a new untracked file
号
这就是你出错的地方。
只有在添加了文件之后,Git才能从内容中识别它。
你没有准备好你的搜寻者行动的结果。我相信如果你通过finder移动然后执行
对于Xcode用户:如果在Xcode中重命名文件,则会看到徽章图标更改为追加。如果您使用Xcode进行提交,那么实际上会创建一个新文件并丢失历史记录。
解决方法很简单,但在使用Xcode提交之前必须先完成:
重命名:project/oldname.h->project/newname.h重命名:project/oldname.m->project/newname.m
然后返回到Xcode,您将看到徽章从A更改为M,现在保存它以在使用Xcode时提交进一步的更改。
如果您真的需要手动重命名文件,例如,使用脚本批量重命名一组文件,那么使用