在 git 中处理文件重命名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2641146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handling file renames in git
提问by Greg K
I'd read that when renaming files in git, you should commit any changes, perform your rename and then stage your renamed file. Git will recognise the file from the contents, rather than seeing it as a new untracked file, and keep the change history.
我读到在 git 中重命名文件时,您应该提交任何更改,执行重命名,然后暂存重命名的文件。Git 将根据内容识别文件,而不是将其视为新的未跟踪文件,并保留更改历史记录。
However, doing just this tonight I ended up reverting to git mv
.
但是,今晚就这样做,我最终恢复到git mv
.
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
Rename my stylesheet in Finder from iphone.css
to mobile.css
在 Finder 中将我的样式表重命名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
So git now thinks I've deleted one CSS file, and added a new one. Not what I want, lets undo the rename and let git do the work.
所以 git 现在认为我已经删除了一个 CSS 文件,并添加了一个新文件。不是我想要的,让我们撤消重命名并让 git 完成工作。
> $ git reset HEAD .
Unstaged changes after reset:
M css/iphone.css
M index.html
Back to where I began.
回到我开始的地方。
> $ git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: index.html
#
Lets use git mv
instead.
让我们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
#
Looks like we're good. So why didn't git recognise the rename the first time around when I used Finder?
看起来我们很好。那么为什么当我第一次使用 Finder 时 git 没有识别重命名呢?
采纳答案by tanascius
For git mv
the
manual pagesays
对于git mv
该
手册说
The index is updated after successful completion, […]
成功完成后更新索引,[…]
So, at first, you have to update the index on your own
(by using git add mobile.css
). Howevergit status
will still show two different files
因此,首先,您必须自己更新索引(通过使用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
#
You can get a different output by running
git commit --dry-run -a
, which results in what you
expect:
您可以通过运行获得不同的输出
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
#
I can't tell you exactly why we see these differences
between git status
andgit commit --dry-run -a
, but
here is a hint from
Linus:
我不能确切地告诉你为什么我们会看到git status
和之间的这些差异git commit --dry-run -a
,但这里有一个来自Linus的提示
:
git really doesn't even careabout the whole "rename detection" internally, and any commits you have done with renames are totally independent of the heuristics we then use to showthe renames.
git 甚至根本不关心内部的整个“重命名检测”,并且您使用重命名所做的任何提交都完全独立于我们用来显示重命名的启发式方法。
A dry-run
uses the real renaming mechanisms, while a
git status
probably doesn't.
Adry-run
使用真正的重命名机制,而 a
git status
可能没有。
回答by nonrectangular
You have to add the two modified files to the index before git will recognize it as a move.
在 git 将其识别为移动之前,您必须将两个修改后的文件添加到索引中。
The only difference between mv old new
and git mv old new
is that the git mv also adds the files to the index.
mv old new
和之间的唯一区别git mv old new
是 git mv 还将文件添加到索引中。
mv old new
then git add -A
would have worked, too.
mv old new
那么git add -A
也会起作用。
Note that you can't just use git add .
because that doesn't add removals to the index.
请注意,您不能只使用,git add .
因为这不会向索引添加删除。
回答by dimuthu
Best thing is to try it for yourself.
最好的办法是亲自尝试。
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
Now git status and git commit --dry-run -a shows two different results where git status shows bbb.txt as a new file/ aaa.txt is deleted, and the --dry-run commands shows the actual rename.
现在 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
#
Now go ahead and do the check-in.
现在继续办理登机手续。
git commit -a -m "Rename"
Now you can see that the file is in fact renamed, and what's shown in git status is wrong.
现在您可以看到该文件实际上已重命名,并且 git status 中显示的内容是错误的。
Moral of the story: If you're not sure whether your file got renamed, issue a "git commit --dry-run -a". If its showing that the file is renamed, you're good to go.
故事寓意:如果您不确定您的文件是否已重命名,请发出“git commit --dry-run -a”。如果它显示文件已重命名,那么您就可以开始了。
回答by GrigorisG
For git 1.7.x the following commands worked for me:
对于 git 1.7.x,以下命令对我有用:
git mv css/iphone.css css/mobile.css
git commit -m 'Rename folder.'
There was no need for git add, since the original file (i.e. css/mobile.css) was already in the committed files previously.
不需要 git add,因为原始文件(即 css/mobile.css)之前已经在提交的文件中。
回答by knittl
you have to git add css/mobile.css
the new file and git rm css/iphone.css
, so git knows about it. then it will show the same output in git status
你必须git add css/mobile.css
使用新文件 and git rm css/iphone.css
,所以 git 知道它。然后它将显示相同的输出git status
you can see it clearly in the status output (the new name of the file):
您可以在状态输出(文件的新名称)中清楚地看到它:
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
and (the old name):
和(旧名称):
# Changed but not updated:
# (use "git add/rm <file>..." to update what will be committed)
i think behind the scenes git mv
is nothing more than a wrapper script which does exactly that: delete the file from the index and add it under a different name
我认为幕后git mv
只不过是一个包装脚本,它正是这样做的:从索引中删除文件并以不同的名称添加它
回答by albfan
Let's think about your files from git perspective.
让我们从 git 的角度考虑您的文件。
Keep in mind git doesn't track any metadata about your files
请记住,git 不会跟踪有关您文件的任何元数据
Your repository has (among others)
您的存储库具有(除其他外)
$ cd repo
$ ls
...
iphone.css
...
and it is under git control:
它在 git 控制之下:
$ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked
file is tracked
Test this with:
测试这个:
$ touch newfile
$ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked
(no output, it is not tracked)
$ rm newfile
When you do
当你做
$ mv iphone.css mobile.css
From git perspective,
从git的角度来看,
- there is no iphone.css(it is deleted -git warns about that-).
- there is a new file mobile.css.
- Those files are totally unrelated.
- 没有iphone.css(它被删除 -git 警告 -)。
- 有一个新文件mobile.css。
- 这些文件完全不相关。
So, git advises about files it already knows (iphone.css) and new files it detects (mobile.css) but only when files are in index or HEAD git starts to check their contents.
因此,git 会建议它已经知道的文件 ( iphone.css) 和它检测到的新文件 ( mobile.css),但仅当文件位于索引中或 HEAD git 开始检查其内容时。
At this moment, neither "iphone.css deletion" nor mobile.cssare on index.
此时,“iphone.css 删除”和mobile.css都不在索引上。
Add iphone.css deletion to index
将 iphone.css 删除添加到索引
$ git rm iphone.css
git tells you exactly what has happened: (iphone.cssis deleted. Nothing more happened)
git 告诉你到底发生了什么:(iphone.css被删除。没有更多的事情发生)
then add new file mobile.css
然后添加新文件mobile.css
$ git add mobile.css
This time both deletion and new file are on index. Now git detects context are the same and expose it as a rename. In fact if files are 50% similar it will detect that as a rename, that let you change mobile.cssa bit while keeping the operation as a rename.
这次删除和新文件都在索引上。现在 git 检测上下文是相同的并将其公开为重命名。事实上,如果文件有 50% 的相似性,它会将其检测为重命名,这让您可以稍微更改mobile.css,同时将操作保持为重命名。
See this is reproducible on git diff
. Now that your files are on index you must use --cached
. Edit mobile.cssa bit, add that to index and see the difference between:
看到这是可重现的git diff
。现在您的文件在索引上,您必须使用--cached
. 稍微编辑mobile.css,将其添加到 index 并查看两者之间的区别:
$ git diff --cached
and
和
$ git diff --cached -M
-M
is the "detect renames" option for git diff
. -M
stands for -M50%
(50% or more similarity will make git express it as a rename) but you can reduce this to -M20%
(20%) if you edit mobile.css a lot.
-M
是“检测重命名”选项git diff
。-M
代表-M50%
(50% 或更多的相似性将使 git 将其表示为重命名)但-M20%
如果您经常编辑 mobile.css,您可以将其减少到(20%)。
回答by Haimei
Step1: rename the file from oldfile to newfile
步骤1:将文件从旧文件重命名为新文件
git mv #oldfile #newfile
Step2: git commit and add comments
Step2: git commit 并添加注释
git commit -m "rename oldfile to newfile"
Step3: push this change to remote sever
步骤 3:将此更改推送到远程服务器
git push origin #localbranch:#remotebranch
回答by hasen
Git will recognise the file from the contents, rather than seeing it as a new untracked file
Git 将从内容中识别文件,而不是将其视为新的未跟踪文件
That's where you went wrong.
那就是你出错的地方。
It's only afteryou add the file, that git will recognize it from content.
只有在添加文件后,git 才会从内容中识别它。
回答by Mike Seplowitz
You didn't stage the results of your finder move. I believe if you did the move via Finder and then did git add css/mobile.css ; git rm css/iphone.css
, git would compute the hash of the new file and only then realize that the hashes of the files match (and thus it's a rename).
你没有上演你的发现者移动的结果。我相信如果您通过 Finder 进行了移动,然后git add css/mobile.css ; git rm css/iphone.css
git 会计算新文件的哈希值,然后才意识到文件的哈希值匹配(因此它是重命名)。
回答by pckben
In cases where you really have to rename the files manually, for eg. using a script to batch rename a bunch of files, then using git add -A .
worked for me.
在您确实必须手动重命名文件的情况下,例如。使用脚本批量重命名一堆文件,然后使用git add -A .
对我有用。