如何将git标记为已删除的文件并将新文件作为文件移动?

时间:2009-01-11 16:01:09

标签: git

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

15 个答案:

答案 0 :(得分:364)

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

另外,对于目录周围的移动,您可能需要:

  1. cd到该目录结构的顶部。
  2. 运行git add -A .
  3. 运行git status以验证“新文件”现在是“重命名”文件
  4. 如果git状态仍然显示“新文件”而不是“重命名”,则需要遵循Hank Gay’s建议,并在两次单独的提交中进行移动和修改。

答案 1 :(得分:87)

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

答案 2 :(得分:43)

这都是一种感性的东西。 Git通常擅长识别移动,因为 GIT 内容跟踪器

真正取决于你的“统计”如何显示它。这里唯一的区别是-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

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帮助日志

   -M
       Detect renames.

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

答案 3 :(得分:29)

git diff -Mgit log -M应自动将此类更改检测为重命名并进行微小更改,只要确实如此。 如果您的次要更改不是次要的,您可以减少相似性threashold,例如

$ git log -M20 -p --stat

将其从默认的50%降低到20%。

答案 4 :(得分:27)

这是一个快速而又脏的解决方案,适用于未提交的一个或几个重命名和修改过的文件。

假设该文件名为foo,现在名为bar

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

    mv bar side
    
  2. 结帐foo

    git checkout HEAD foo
    
  3. 使用Git将foo重命名为bar

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

    mv side bar
    
  5. 最后一步是将更改的内容恢复到文件中。

    虽然这可行,但如果移动的文件与原始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.
    

答案 5 :(得分:17)

如果您说的是git status没有显示重命名,请尝试使用git commit --dry-run -a

答案 6 :(得分:10)

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

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

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

这里提出了同样的问题:https://tortoisegit.org/issue/1389并且已经记录为在此处修复的错误:https://tortoisegit.org/issue/1440事实证明这是TortoiseGit的提交对话框的显示问题,并且还存在于git状态如果你还没有添加新文件。

答案 7 :(得分:3)

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

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

答案 8 :(得分:3)

或者你可以通过here尝试这个问题Amber的答案! 再次引用它:

首先,取消手动移动文件的暂存添加:

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

然后,使用Git移动文件:

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

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

答案 9 :(得分:2)

最近,当移动(但没有修改)某些文件时,我遇到了这个问题。

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

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

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

另一种方式是以下

  • 移动文件和git commit。这会更新行结尾。
  • 将文件移回原始位置,现在他们有新的行结尾,git commit --amend
  • 再次移动文件git commit --amend。这次线路结尾没有变化,所以Git很高兴

答案 10 :(得分:1)

对我来说,它可以在提交之前保存所有更改并再次弹出它们。这使得git重新分析添加/删除的文件,并正确地将它们标记为已移动。

答案 11 :(得分:0)

有一个更好的“命令行”方法可以做到这一点,我知道这是一个黑客,但我从来没有找到一个好的解决方案。

使用TortoiseGIT:如果你有一个GIT提交,其中某些文件移动操作显示为加载/删除的加载而不是重命名,即使文件只有很小的更改,那么执行以下操作:

  1. 检查您在当地做了什么
  2. 在第二次提交中检入迷你单行更改
  3. 转到GIT登录tortoise git
  4. 选择两个提交,右键单击,然后选择“合并为一个提交”
  5. 新提交现在将正确显示文件重命名...这将有助于维护正确的文件历史记录。

答案 12 :(得分:0)

当我同时编辑,重命名和移动文件时,这些解决方案都不起作用。解决方案是在两次提交(编辑和重命名/移动单独)中进行,然后fixup通过git rebase -i进行第二次提交,以便在一次提交中进行。

答案 13 :(得分:0)

我对这个问题的理解是“如何让git识别旧文件的删除以及在文件移动时创建新文件”。

在工作目录中,一旦您删除了旧文件并插入了旧文件,git status就会说“ deleted: old_file”和“ Untracked files: ... new_file

但是在暂存索引/级别中,一旦您使用git添加和删除文件,它将被识别为文件移动。为此,假设您已经使用操作系统完成了删除和创建,请输入以下命令:

git add new_file
git rm old_file

如果文件的内容相似度超过50%,则运行git status命令应为您提供:

renamed: old_file -> new_file

答案 14 :(得分:0)

其他答案已经涵盖了,您可以简单地git add NEW && git rm OLD来使git识别移动。

但是,如果您已经修改了工作目录中的文件,则add + rm方法将对索引添加修改,这在某些情况下可能是不希望的(例如,在进行大量修改的情况下,git可能不再识别)它是文件重命名)。

让我们假设您想将重命名添加到索引,但是没有任何修改。实现此目的的明显方法是进行来回重命名mv NEW OLD && git mv OLD NEW

但是还有一种(稍微复杂一点)的方法可以直接在索引中执行此操作,而无需重命名工作树中的文件:

info=$(git ls-files -s -- "OLD" | cut -d' ' -f-2 | tr ' ' ,)
git update-index --add --cacheinfo "$info,NEW" &&
git rm --cached "$old"

这也可以作为别名放在您的~/.gitconfig中:

[alias]
    mv-index = "!f() { \
      old=\"$1\"; \
      new=\"$2\"; \
      info=$(git ls-files -s -- \"$old\" | cut -d' ' -f-2 | tr ' ' ,); \
      git update-index --add --cacheinfo \"$info,$new\" && \
      git rm --cached \"$old\"; \
    }; f"