奇怪的`git mv`行为 [英] Odd `git mv` behaviour

查看:129
本文介绍了奇怪的`git mv`行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

上个月,我开始为GitHub存储库贡献一份相应的回购,创建一个功能分支,然后提交一个pull请求。在重复这个过程几天的过程中,当使用预安装的Linux命令 mv 重命名文件并且使用Git命令<$ c $时,我遇到了一个奇怪的问题c> git mv 。



实际的问题是,根据何时移动/重命名文件 git mv ,当你 git add 它,并且在你编辑重命名文件的时候,你可以得到:

 关于分支大师
要提交的更改:
(使用git reset HEAD< file> ...停用)

已更名为:somethingelse - >

或者:

 关于分支大师
要提交的更改:
(使用git reset HEAD< file> ...来暂停)

新文件:something
deleted:somethingelse

为了证明这一点,我写了一个 test

 #!/ bin / bash 

#据我所知,这个问题只发生在Git仓库中的新文件
printfCOMMAND:mkdir -v gitrepo \\\
\\\

mkdir -v gitrepo

printf\ nCOMMAND:cd gitrepo \\\
\\\

cd gitrepo

printf\\\
COMMAND:git init\\\
\\\

git init

printf\ nCOMMAND:git status\\\
\\\

git status

printf\ nCOMMAND:touch something\\\
\\\

touch something

printf\\\
COMMAND:git status\\\
\\\

git status

printf\\\
COMMAND:git add something\ n'\

git add something

printf\\\
COMMAND:git status\\\
\\\

git status

printf '\\\
COMMAND:git commit -m添加了一些内容\\\
\\\
'
git commit -m添加了一些内容

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

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

git mv something somethingelse

printf\ nCOMMAND:git status \\\
\\\

git status

#在第一行输入以下内容:第一行代码
printf \\\
COMMAND:vim somethingelse \\\
\\\

vim somethingelse

printf\ nCOMMAND:git status\\\
\\\

git status

printf\\\
COMMAND:git add somethingelse \\\
\\\

git add somethingelse

printf \ nCOMMAND:git status \\\
\\\

git status

printf'\\\
COMMAND:git commit -m将某些东西重命名为somethingelse并编辑somethingelse\ n \\ \\ n'
git commit -m将某些东西重命名为somethingelse并编辑somethingelse

printf\ nCOMMAND:git status \\\
\\\

git status

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

git mv somethingelse something

printf\\\
COMMAND:git status\ n \ n
git status

#如果您在第一行添加了某些内容,重命名将不会被Git
#检测到但是,如果您改为创建2个换行符并用新代码填充第3行,
#无论出于何种原因都会检测到重命名
printf\\\
COMMAND:vim something\\\
\\\

vim something

printf\ nCOMMAND:git status \\\
\\\

git status

printf\\\
COMMAND:git add something\\\
\\\

git add s omething

printf\ nCOMMAND:git status\\\
\\\

git status
$ b printf'\ nCOMMAND:git commit -m更名somethingelse to something and edited something\\\
\\\
'
git commit -m将somethingelse重命名为某些内容并编辑了一些内容

printf\ nCOMMAND:git status \\\
\\\

git status

cd ..&& rm -fr gitrepo&& printf\\\
REMOVED gitrepo folder \\\

printf\\\
DONE.\\\

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



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



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



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

解决方案

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

  git mv oldname newname 

#完全等价于:

mv oldname newname
git rm oldname
git add newname

显示文件状态时, git 通过比较内容,尝试猜测它是否是重命名 delete + add 看看它们有多相似。



所以:如果你从 git mv 开始一个文件,并且然后编辑该文件,具体取决于文件的修改量,git可能会或可能无法看到它全部以 mv 开头。



另请参阅此问题的答案: Git如何知道文件被重命名? / p>

Last month I started to contribute to a GitHub repository by forking the corresponding repo, creating a feature branch and then submitting a pull request. While repeating that process for a couple of days, I ran into a weird problem when renaming files with the pre-installed Linux command mv and also with the Git command git mv.

The actual problem is, that depending on when you move/rename a file with git mv, when you git add it and at what point you edit the renamed file, you either get:

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

        renamed:    somethingelse -> something

Or this:

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

        new file:   something
        deleted:    somethingelse

To demonstrate this, I have written a 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"

For some reason, this mostly affects "new files" and not the ones which already exist in a repository. If you clone my fork of the Spoon-Knife repository with git clone https://github.com/christianheinrichs/Spoon-Knife.git for example and then apply the work flow of the linked test script, you will see that in most cases you will be able to rename the README.md file to README for example, edit it and it will still count as a rename instead of a new file/deleted split.

Although I could reproduce the new file/deleted behavior on the cloned Spoon-Knife fork repo, I am not exactly sure how I did that and believe me when I say that I tried to figure it out.

So what exactly is going on here that I don't understand?

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

解决方案

git does not keep a flag saying "this newname file was initially called oldname file" :

git mv oldname newname

# is exactly equivalent to :  

mv oldname newname
git rm oldname
git add newname

When displaying the status of a file, git tries to guess if it was a rename or a delete + add by comparing the content of the files, and seeing how similar they are.

So : if you start by git mv a file, and then edit the file, depending on how much the file is modified, git may or may not be able to see that it all started with a mv.

See also the answer to this question : How does Git know that file was renamed?

这篇关于奇怪的`git mv`行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆