2017-09-15 82 views
1

上个月,我开始贡献一个GitHub仓库,通过分叉相应的回购,创建一个功能分支,然后提交一个pull请求。在重复此过程几天的过程中,当使用预安装的Linux命令mv以及Git命令git mv重命名文件时,我遇到了一个奇怪的问题。奇怪的`git mv`行为

实际的问题是,这取决于当你移动/上重命名文件与git mv,当你git add它和在什么时候你编辑重命名的文件,你要么:

On branch master 
Changes to be committed: 
    (use "git reset HEAD <file>..." to unstage) 

     renamed: somethingelse -> something 

或者这样:

On branch master 
Changes to be committed: 
    (use "git reset HEAD <file>..." to unstage) 

     new file: something 
     deleted: somethingelse 

为了证明这一点,我已经写了test

#!/bin/bash 

# To my knowledge, this “problem” only occurs with new files in a Git repo 
printf "COMMAND: mkdir -v gitrepo\n\n" 
mkdir -v gitrepo 

printf "\nCOMMAND: cd gitrepo\n\n" 
cd gitrepo 

printf "\nCOMMAND: git init\n\n" 
git init 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: touch something\n\n" 
touch something 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: git add something\n\n" 
git add something 

printf "\nCOMMAND: git status\n\n" 
git status 

printf '\nCOMMAND: git commit -m "Added something"\n\n' 
git commit -m "Added something" 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: git mv something somethingelse\n\n" 
git mv something somethingelse 

printf "\nCOMMAND: git status\n\n" 
git status 

# Type in the following on line 1: First line of code 
printf "\nCOMMAND: vim somethingelse\n\n" 
vim somethingelse 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: git add somethingelse\n\n" 
git add somethingelse 

printf "\nCOMMAND: git status\n\n" 
git status 

printf '\nCOMMAND: git commit -m "Renamed something to somethingelse and edited somethingelse"\n\n' 
git commit -m "Renamed something to somethingelse and edited somethingelse" 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: git mv somethingelse something\n\n" 
git mv somethingelse something 

printf "\nCOMMAND: git status\n\n" 
git status 

# If you add something to the first line, the rename will not be detected by Git 
# However, if you instead create 2 newlines and fill line 3 with new code, 
# the rename gets detected for whatever reason 
printf "\nCOMMAND: vim something\n\n" 
vim something 

printf "\nCOMMAND: git status\n\n" 
git status 

printf "\nCOMMAND: git add something\n\n" 
git add something 

printf "\nCOMMAND: git status\n\n" 
git status 

printf '\nCOMMAND: git commit -m "Renamed somethingelse to something and edited something"\n\n' 
git commit -m "Renamed somethingelse to something and edited something" 

printf "\nCOMMAND: git status\n\n" 
git status 

cd .. && rm -fr gitrepo && printf "\nREMOVED gitrepo folder\n" 
printf "\nDONE.\n" 

出于某种原因,这主要影响“新文件”,而不是已存在于存储库中的文件。例如,如果您将Spoon-Knife repository的分支克隆为git clone https://github.com/christianheinrichs/Spoon-Knife.git,然后应用链接测试脚本的工作流程,您将看到在大多数情况下,您将能够将README.md文件重命名为README,例如对其进行编辑,它仍然算作重命名而不是新文件/删除分割。

尽管我可以在克隆的勺子刀叉回购中重现新文件/删除行为,但我不确定我是如何做到这一点的,并且当我说我试图弄清楚时相信我。

那么究竟发生了什么,我不明白?

参见:https://gist.github.com/christianheinrichs/e50bfdd5eec70a606fa6ce4a88c5951b#file-git_mv-test-sh-L65

回答

4

git不保留一个标志说:“这newname文件最初被称为oldname文件”:

git mv oldname newname 

# is exactly equivalent to : 

mv oldname newname 
git rm oldname 
git add newname 

当显示文件的状态,git试图猜测,如果它是renamedelete + add通过比较文件的内容,并看到它们是多么相似。所以:如果你从git mv开始文件,然后编辑文件,取决于文件被修改了多少,git可能会或可能不会看到它全部以mv开头。

又见这个问题的答案:How does Git know that file was renamed?

+1

还要注意的是,当你运行'git diff'您可以启用或禁用重命名的检测,并设置“相似度阈值”号。当'git status'为你运行'git diff'时,对于这种情况,它将相似性阈值设置为50%:重命名检测总是打开,并且阈值是固定的。 – torek

+0

@torek我假设你正在谈论'git diff -M [], - 查找重命名[= ]'?这是我不知道的一个很好的功能,可能会在第二个问题中部分解释这个问题。 –

+0

@LeGEC谢谢你的回答。但是,在我接受它之前,您能否在我附加的第二个问题中解释Git行为? '另外,为什么Git没有检测到重命名,如果你添加了一些东西到第一行,但是如果你创建了2个换行符并用新代码填充第3行,那么为什么不检测这个重命名?' –