2017-09-15 77 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行,那麼爲什麼不檢測這個重命名?' –