如何使 git 将删除的文件和新文件标记为文件移动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/433111/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 06:03:40  来源:igfitidea点击:

How to make git mark a deleted and a new file as a file move?

git

提问by pupeno

I've moved a file manually and then I've modified it. According to Git, it is a new file and a removed file. Is there any way to force Git into treating it as a file move?

我手动移动了一个文件,然后我修改了它。根据 Git,它是一个新文件和一个已删除的文件。有没有办法强制 Git 将其视为文件移动?

采纳答案by Bombe

Git will automatically detect the move/rename if your modification is not too severe. Just git addthe new file, and git rmthe old file. git statuswill then show whether it has detected the rename.

如果您的修改不是太严重,Git 将自动检测移动/重命名。只是git add新文件和git rm旧文件。git status然后将显示它是否已检测到重命名。

additionally, for moves around directories, you may need to:

此外,要在目录中移动,您可能需要:

  1. cd to the top of that directory structure.
  2. Run git add -A .
  3. Run git statusto verify that the "new file" is now a "renamed" file
  1. cd 到该目录结构的顶部。
  2. git add -A .
  3. 运行git status以验证“新文件”现在是“重命名”文件

If git status still shows "new file" and not "renamed" you need to follow Hank Gay'sadvice and do the move and modify in two separate commits.

如果 git status 仍然显示“新文件”而不是“重命名”,您需要遵循Hank Gay 的建议并在两个单独的提交中进行移动和修改。

回答by Hank Gay

Do the move and the modify in separate commits.

在单独的提交中进行移动和修改。

回答by Kent Fredric

It's all a perceptual thing. Git is generally rather good at recognising moves, because GITis a content tracker

这都是感性的事情。Git 通常很擅长识别动作,因为GIT是一个内容跟踪器

All that really depends is how your "stat" displays it. The only difference here is the -M flag.

真正取决于您的“统计数据”如何显示它。这里唯一的区别是 -M 标志。

git log --stat -M

git log --stat -M

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300


        Category Restructure

     lib/Gentoo/Repository.pm                |   10 +++++-----
     lib/Gentoo/{ => Repository}/Base.pm     |    2 +-
     lib/Gentoo/{ => Repository}/Category.pm |   12 ++++++------
     lib/Gentoo/{ => Repository}/Package.pm  |   10 +++++-----
     lib/Gentoo/{ => Repository}/Types.pm    |   10 +++++-----
     5 files changed, 22 insertions(+), 22 deletions(-)

git log --stat

git log --stat

commit 9c034a76d394352134ee2f4ede8a209ebec96288
Author: Kent Fredric
Date:   Fri Jan 9 22:13:51 2009 +1300

    Category Restructure

 lib/Gentoo/Base.pm                |   36 ------------------------
 lib/Gentoo/Category.pm            |   51 ----------------------------------
 lib/Gentoo/Package.pm             |   41 ---------------------------
 lib/Gentoo/Repository.pm          |   10 +++---
 lib/Gentoo/Repository/Base.pm     |   36 ++++++++++++++++++++++++
 lib/Gentoo/Repository/Category.pm |   51 ++++++++++++++++++++++++++++++++++
 lib/Gentoo/Repository/Package.pm  |   41 +++++++++++++++++++++++++++
 lib/Gentoo/Repository/Types.pm    |   55 +++++++++++++++++++++++++++++++++++++
 lib/Gentoo/Types.pm               |   55 -------------------------------------
 9 files changed, 188 insertions(+), 188 deletions(-)

git help log

git 帮助日志

   -M
       Detect renames.

   -C
       Detect copies as well as renames. See also --find-copies-harder.

回答by Kent Fredric

git diff -Mor git log -Mshould automatically detect such changes as a rename with minor changesas long as they indeed are. If your minor changesare not minor, you can reduce the similarity threashold, e.g.

git diff -M或者git log -M应该自动检测这样的更改,例如重命名,只要它们确实是微小的更改。如果你的小改动不小,你可以降低相似度阈值,例如

$ git log -M20 -p --stat

to reduce it from the default 50% to 20%.

将其从默认的 50% 减少到 20%。

回答by Kent Fredric

Here's a quick and dirty solution for one, or a few, renamed and modified files that are uncommitted.

这是一个或几个未提交的重命名和修改文件的快速而肮脏的解决方案。

Let's say the file was named fooand now it's named bar:

假设文件被命名foo,现在它被命名为bar

  1. Rename barto a temp name:

    mv bar side
    
  2. Checkout foo:

    git checkout HEAD foo
    
  3. Rename footo barwith Git:

    git mv foo bar
    
  4. Now rename your temporary file back to bar.

    mv side bar
    
  1. 重命名bar为临时名称:

    mv bar side
    
  2. 结帐foo

    git checkout HEAD foo
    
  3. 使用 Git重命名foobar

    git mv foo bar
    
  4. 现在将您的临时文件重命名回bar.

    mv side bar
    

This last step is what gets your changed content back into the file.

最后一步是将更改后的内容恢复到文件中。

While this can work, if the moved file is too different in content from the original git will consider it more efficient to decide this is a new object. Let me demonstrate:

虽然这可以工作,但如果移动的文件与原始 git 的内容差异太大,则会认为确定这是一个新对象更有效。让我演示一下:

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

    new file:   .gitignore
    renamed:    README -> README.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ git add README.md work.js # why are the changes unstaged, let's add them.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ git stash # what? let's go back a bit
Saved working directory and index state WIP on dir: f7a8685 update
HEAD is now at f7a8685 update
$ git status
On branch workit
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    .idea/

nothing added to commit but untracked files present (use "git add" to track)
$ git stash pop
Removing README
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md

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:    README
    modified:   work.js

Dropped refs/stash@{0} (1ebca3b02e454a400b9fb834ed473c912a00cd2f)
$ git add work.js
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

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:    README

$ git add README # hang on, I want it removed
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    deleted:    README
    new file:   README.md
    modified:   work.js

$ mv README.md Rmd # Still? Try the answer I found.
$ git checkout README
error: pathspec 'README' did not match any file(s) known to git.
$ git checkout HEAD README # Ok the answer needed fixing.
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    new file:   README.md
    modified:   work.js

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:    README.md
    modified:   work.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Rmd

$ git mv README README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   work.js

Untracked files:
  (use "git add <file>..." to include in what will be committed)

    Rmd

$ mv Rmd README.md
$ git status
On branch workit
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   .gitignore
    renamed:    README -> README.md
    modified:   work.js

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   README.md
    modified:   work.js

$ # actually that's half of what I wanted; \
  # and the js being modified twice? Git prefers it in this case.

回答by BoD

If you're talking about git statusnot showing the renames, try git commit --dry-run -ainstead

如果你谈论的是git status没有显示的重命名,尝试git commit --dry-run -a代替

回答by Giles Roberts

If you're using TortoiseGit it's important to note that Git's automatic rename detection happens during commit but the fact that this is going to happen isn't always displayed by the software beforehand. I had moved two files to a different directory and performed some slight edits. I use TortoiseGit as my commit tool and the Changes made list showed the files being deleted and added, not moved. Running git status from the command line showed a similar situation. However after committing the files, they showed up as being renamed in the log. So the answer to your question is, as long as you haven't done anything too drastic, Git should pick up the rename automatically.

如果您正在使用 TortoiseGit,请务必注意 Git 的自动重命名检测在提交期间发生,但软件并不总是事先显示将要发生的事实。我已将两个文件移动到不同的目录并进行了一些轻微的编辑。我使用 TortoiseGit 作为我的提交工具,更改列表显示文件被删除和添加,而不是移动。从命令行运行 git status 显示了类似的情况。但是,在提交文件后,它们在日志中显示为已重命名。所以你的问题的答案是,只要你没有做任何太激烈的事情,Git 应该会自动选择重命名。

Edit: Apparently if you add the new files and then do a git status from the command line, the rename should show up before committing.

编辑:显然,如果您添加新文件,然后从命令行执行 git status,重命名应该在提交之前显示。

Edit 2: In addition, in TortoiseGit, add the new files in the commit dialog but don't commit them. Then if you go into the Show Log command and look at the working directory, you'll see if Git has detected the rename before committing.

编辑 2:此外,在 TortoiseGit 中,在提交对话框中添加新文件但不要提交它们。然后,如果您进入 Show Log 命令并查看工作目录,您将看到 Git 在提交之前是否检测到重命名。

The same question was raised here: https://tortoisegit.org/issue/1389and has been logged as a bug to fix here: https://tortoisegit.org/issue/1440It turns out it's a display issue with TortoiseGit's commit dialog and also kind of exists in git status if you haven't added the new files.

这里提出了同样的问题:https: //tortoisegit.org/issue/1389并已被记录为要在此处修复的错误:https: //tortoisegit.org/issue/1440事实证明这是 TortoiseGit 提交的显示问题如果您尚未添加新文件,则在 git status 中也存在。

回答by Zingam

Or you coud try the answer to this question hereby Amber! To quote it again:

或者你coud尝试回答这个问题,这里琥珀!再次引用它:

First, cancel your staged add for the manually moved file:

首先,取消手动移动文件的分阶段添加:

$ git reset path/to/newfile
$ mv path/to/newfile path/to/oldfile

Then, use Git to move the file:

然后,使用 Git 移动文件:

$ git mv path/to/oldfile path/to/newfile

Of course, if you already committed the manual move, you may want to reset to the revision before the move instead, and then simply git mv from there.

当然,如果您已经提交了手动移动,您可能希望在移动之前重置为修订版,然后从那里简单地 git mv 。

回答by mostafa.elhoushi

Use git mvcommand to move the files, instead of the OS move commands: https://git-scm.com/docs/git-mv

使用git mv命令移动文件,而不是操作系统移动命令:https: //git-scm.com/docs/git-mv

Please note that git mvcommand only exists in Git versions 1.8.5 and up. So you may have to update your Git to use this command.

请注意,该git mv命令仅存在于 Git 版本 1.8.5 及更高版本中。所以你可能需要更新你的 Git 才能使用这个命令。

回答by cedd

I had this problem recently, when moving (but not modifying) some files.

我最近在移动(但不修改)某些文件时遇到了这个问题。

The problem is that Git changed some line endings when I moved the files, and then wasn't able to tell that the files were the same.

问题是当我移动文件时,Git 更改了一些行尾,然后无法判断文件是否相同。

Using git mvsorted out the problem, but it only works on single files / directories, and I had a lot of files in the root of the repository to do.

使用git mv解决了问题,但它仅适用于单个文件/目录,并且我在存储库的根目录中有很多文件要做。

One way of fixing this would be with some bash / batch magic.

解决这个问题的一种方法是使用一些 bash/batch 魔法。

Another way is the following

另一种方法如下

  • Move the files and git commit. This updates the line endings.
  • Move the files back to their original location, now that they have the new line endings, and git commit --amend
  • Move the files again and git commit --amend. There is no change to the line endings this time so Git is happy
  • 移动文件和git commit. 这会更新行尾。
  • 将文件移回其原始位置,现在它们有了新的行尾,并且 git commit --amend
  • 再次移动文件和git commit --amend。这次行尾没有变化,所以 Git 很高兴