奇怪的`git mv`行为

时间:2017-09-15 06:53:46

标签: git github git-mv

上个月,我开始通过分配相应的仓库,创建功能分支然后提交拉取请求来为GitHub存储库做出贡献。在重复该过程几天的过程中,我在使用预安装的Linux命令mv以及Git命令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"

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

虽然我可以在克隆的Spoon-Knife fork repo上重现新文件/已删除的行为,但我并不确定如何做到这一点并相信我,当我说我试图解决它时。

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

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

1 个答案:

答案 0 :(得分:4)

git没有标记&#34;此newname文件最初被称为oldname文件&#34; :

git mv oldname newname

# is exactly equivalent to :  

mv oldname newname
git rm oldname
git add newname

当显示文件的状态时,git会通过比较文件的内容并查看它们的相似程度来尝试猜测它是rename还是delete + add

所以:如果你从git mv开始一个文件,然后编辑文件,根据文件的修改程度,git可能会或者可能看不到它都是以{{1 }}

另请参阅此问题的答案:How does Git know that file was renamed?