gitにファイルの移動として削除済みファイルと新しいファイルをマークさせる方法は?


505

ファイルを手動で移動した後、変更しました。Gitによると、これは新しいファイルであり、削除されたファイルです。Gitに強制的にファイル移動として処理させる方法はありますか?


3
指定したファイルの場合はold_file.txt、その後git mv old_file.txt new_file.txtに相当しgit rm --cached old_file.txtmv old_file.txt new_file.txtgit add new_file.txt
Jarl

3
Jarl:いいえ、そうではありません。ファイル内にも変更git mvがある場合、それらはキャッシュに追加されませんが、追加されgit addます。私は、私が使用できるように、ファイルの背を移動することを好むgit mv、その後、git add -p私の変更セットを検討します。
dhardy 2014

私のスクリプトチェックアウトしてくださいgithub.com/Deathangel908/python-tricks/blob/master/...
deathangel908


Gitは過去8年間で改善されました。ファイルが1つだけの場合、最高の回答であるstackoverflow.com/a/433142/459は何もしませんでした…しかし、stackoverflow.com / a / 1541072/459をフォローしてrm / addを更新できますmv /変更ステータスに。
dlamblin 2017

回答:


435

変更がそれほど厳しくない場合、Gitは移動/名前変更を自動的に検出します。ただ、git add新しいファイル、およびgit rm古いファイル。git status次に、名前の変更を検出したかどうかを示します。

さらに、ディレクトリ内を移動するには、次の操作が必要になる場合があります。

  1. そのディレクトリ構造の最上部に移動します。
  2. 走る git add -A .
  3. git status「新しいファイル」が「名前を変更した」ファイルであることを確認するために実行します

gitステータスに「新しいファイル」が表示され、「名前が変更されていない」場合は、Hank Gayのアドバイスに従って、2つの別々のコミットで移動と変更を行う必要があります。


75
明確化:「それほど厳しくない」とは、gitが使用するいくつかの類似性インデックスに基づいて、新しいファイルと古いファイルが50%以上「類似」していることを意味します。
pjz

151
名前が変更されたファイルと削除されたファイルがコミットのステージングされていない場合、それらは削除と新しいファイルとして表示されます。それらをステージングインデックスに追加すると、名前変更として認識されます。
marczych

19
Gitが移動/名前変更を自動的に検出するいえば、言及する価値があります。それはあなたが使用時にそれを行うgit statusgit logまたはgit diffないあなたが一度にgit addgit mvまたはgit rm。名前の変更の検出についてさらに言えば、ステージングされたファイルに対してのみ意味があります。したがって、git mvファイルに変更が続くgit statusと、それはと見なされているように見えますが、ファイルで(と同じ)renameを使用すると、変更が大きすぎて名前の変更として検出できないことが明らかになります。git stagegit add
Jarl

5
本当の鍵は、新しい場所と古い場所の両方を同じに追加することですgit add。これは、@ jrhorn424が示唆しているように、おそらく一度にリポジトリ全体である必要があります。
ブライアリー

4
ただし、特にファイルが変更されてサイズが小さい場合は、これは間違いありません。移動を具体的にGitに伝える方法はありますか?
Rebs

112

移動と変更を別々のコミットで実行します。


12
Gitは移動と変更を同時に処理できることを理解しています。Javaでプログラミングし、IDEを使用する場合、クラスの名前を変更することは、変更と移動の両方です。移動(削除と作成から)があったときに、Gitが自動的にそれを理解できるようにする必要があることを理解しています。
プペノ2009年

1
Perlもこれを必要とし、Gitに移動/名前の変更を検出させたことはありません。
jrockway 2009年

10
@jrockway、持っていました。小さなファイルで簡単に起こります。それらは「移動することを意味するために「あまりにも異なる」になります」と思います。
ANeves

2
これを自動化する方法はありますか?インデックスに多くのファイルがあり、最初に移動をコミットし、次に変更をコミットしたいのですが、手動で行うのは難しい
ReDetection

5
1つの注意点は、git diff1つのコミットで名前の変更を認識しない場合、2つのコミットで名前の変更を認識しないことです。それには-M別名--find-renamesを使用する必要があります。したがって、この質問にあなたを導いた動機が(経験から言えば)プルリクエストで名前の変更を確認することである場合、それを2つのコミットに分割しても、その目標に向かって進むことはできません。
mattliu 2017年

44

それはすべて知覚的なものです。GITコンテンツトラッカーであるため、Gitは一般に動きの認識に優れています

実際に依存するのは、「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

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

   -M
       Detect renames.

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

76
これは少し奇妙に思われる場合は申し訳ありませんが、「GITはコンテンツトラッカーであるため、Gitは一般に動きの認識に優れています」と私には不平等ではないようです。それはコンテンツトラッカーです。そうです。たぶん、たまたま動きを検出するのは得意ですが、1つのステートメントが実際に他のステートメントに従っているわけではありません。コンテンツトラッカーだからといって、動きの検出は必ずしも良いとは限りません。実際、コンテンツトラッカーでは、移動をまったく検出できません。
Laurence Gonsalves

1
@WarrenSeineディレクトリの名前を変更しても、そのディレクトリ内のファイルのSHA1は変更​​されません。必要なのは、同じSHA1を持つ新しいTREEオブジェクトだけです。ディレクトリの名前を変更してもデータに重大な変更が生じる理由はありません。
ケントフレドリック14

1
@KentFredric「Mit log」で-Mを使用すると、ファイルの名前が変更されているかどうかを確認でき、それを試してみましたが、コードをレビューのために投稿し、そのファイルをgerrit(gerritcodereview.com)で確認するとそこでは、ファイルが新しく追加され、以前に削除されたことを示しています。「git commit」には、私がコミットしてgerritがそれを適切に表示するオプションがあります。
Patrick

1
いいえ、まったく表示しませんでした。内容が同じであるため、Gitが追加+削除が名前の変更を装うことができることを示しました。どちらが起こった知る方法はなく、気にしない。gitが覚えているのは「追加」と「削除」です。「名前を変更」は記録されません。
ケントフレドリック

1
たとえば、最近、リポジトリで「コピー+編集」をたくさん行いました。ほとんどの表示方法では「新しいファイル」しか表示されませんがgit log -M1 -C1 -B1 -D --find-copies-harder、を渡すと、gitは新しいファイルが最初にコピーされた可能性があることを「検出」できます。時々これを正しく行うこともあれば、まったく同じ内容の偶然に無関係なファイルを見つけることもあります。
ケントフレドリック

36

git diff -Mまたは、実際にそうである限り、マイナーな変更を伴う名前変更git log -Mなどの変更を自動的に検出する必要があります。あなたの場合は軽微な変更は軽微なものではなく、あなたが類似threasholdを減らすことができ、例えば

$ git log -M20 -p --stat

デフォルトの50%から20%に減らします。


13
構成でしきい値を定義することは可能ですか?
ReDetection 2016

34

以下は、コミットされていない1つまたはいくつかの名前が変更および変更されたファイルの迅速でダーティなソリューションです。

ファイルに名前が付けられていて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
    

この最後のステップは、変更されたコンテンツをファイルに戻すものです。

これは機能しますが、移動したファイルのコンテンツが元の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.

27
このプロセスは目的を果たしません。gitは名前を変更するためのメタデータを追加せず、git mv単にgit rm/ git addペアの利便性を高めます。すでに「MVバーfoo」でやった場合は、すべてあなたがしなければならないが、あなたがしたことを確認するgit add foogit rm barコミット行う前に。これは、単一のgit add -Aコマンドまたは場合によってはgit add foo; git commit -aシーケンスと同じように実行できます。
CBベイリー

17
私が知っているのは、私がそれを行う前は、Gitがそれを移動として認識していなかったことだけです。私がこれを行った後、Gitはそれを動きとして認識しました。

8
それは動きとして認識します。しかし、現在は段階的な変更としての変更もあります。もう一度addファイルを作成すると、gitは移動/変更を削除/追加に分割します。
Michael Piefel

4
このプロセスはgit commit、ステップ3の後であれば機能しますが、そうでない場合は正しくありません。また、@ CharlesBaileyは正解です。mv blah fooステップ3で通常どおりに簡単に通常の操作を行ってからコミットを実行すると、同じ結果が得られます。
DaFlame、2014

5
「このプロセスには意味がありません。」-gitが混乱し、ファイルが削除され、別のファイルが追加されたと考える場合に役立ちます。これにより、Gitの混乱が解消され、中間コミットを行わなくても、ファイルが明示的に移動済みとしてマークされます。
Danack

20

git status名前の変更を表示しないことについて話している場合は、git commit --dry-run -a代わりに試してください


11

TortoiseGitを使用している場合、Gitの自動名前変更検出はコミット中に発生することに注意することが重要ですが、これが発生するという事実は常にソフトウェアによって常に表示されるとは限りません。2つのファイルを別のディレクトリに移動し、少し編集を行いました。私は自分のコミットツールとしてTortoiseGitを使用しており、[行った変更]リストには、移動ではなく削除および追加されるファイルが表示されていました。コマンドラインからgit statusを実行すると、同様の状況が示されました。ただし、ファイルをコミットした後、ログで名前が変更されたことがわかりました。だからあなたの質問への答えは、あなたがあまりにも極端なことを何もしていない限り、Gitは自動的に名前変更をピックアップするべきです。

編集:どうやら新しいファイルを追加してからコマンドラインからgit statusを実行すると、コミットする前に名前の変更が表示されるはずです。

編集2:さらに、TortoiseGitで、コミットダイアログに新しいファイルを追加しますが、コミットはしません。次に、[ログの表示]コマンドに移動して作業ディレクトリを確認すると、コミットする前にGitが名前の変更を検出したかどうかを確認できます。

同じ質問がここで提起されました:https : //tortoisegit.org/issue/1389そしてここで修正するためにバグとして記録されています:https : //tortoisegit.org/issue/1440 それはTortoiseGitのコミットに関する表示の問題であることがわかりましたダイアログがあり、新しいファイルを追加していない場合はgitステータスにも存在します。


2
TortoiseGitに削除+追加が表示されていても、gitステータスに削除+追加が表示されていても、git commit --dry-runに削除+追加が表示されていても、git commit後に名前の変更が表示され、削除+追加は表示されません。
Tomas Kubes 2014年

1
名前の自動検出は履歴の取得中に行われると思います。コミットでは常にadd + deleteです。それはまたあなたが説明する統合失調症の行動を説明します。したがって、ここでのオプション:stackoverflow.com/a/434078/155892
Mark Sowul

10

それとも、この質問への答えをしてみてくださいcoud ここ琥珀!もう一度引用するには:

まず、手動で移動したファイルの段階的な追加をキャンセルします。

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

次に、Gitを使用してファイルを移動します。

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

もちろん、すでに手動の移動をコミットしている場合は、移動前のリビジョンにリセットして、そこからgit mvを実行することもできます。


7

git mvOSの移動コマンドではなく、コマンドを使用してファイルを移動します。https//git-scm.com/docs/git-mv

このgit mvコマンドはGitバージョン1.8.5以降にのみ存在することに注意してください。したがって、このコマンドを使用するにはGitを更新する必要がある場合があります。


3

最近、一部のファイルを移動(変更はしない)するときにこの問題が発生しました。

問題は、ファイルを移動したときにGitが一部の行末を変更したため、ファイルが同じであることを認識できなかったことです。

git mv問題を整理して使用しましたが、それは単一のファイル/ディレクトリでのみ機能し、リポジトリのルートに実行する多くのファイルがありました。

これを修正する1つの方法は、bash /バッチマジックを使用することです。

別の方法は次のとおりです

  • ファイルとを移動しますgit commit。これにより、行末が更新されます。
  • 新しい行末があるため、ファイルを元の場所に戻します。 git commit --amend
  • ファイルを再度移動しますgit commit --amend。今回は行末に変更がないため、Gitは満足しています

1

私にとっては、コミットする前にすべての変更を隠して保存し、再びそれらをポップアウトすることができました。これにより、gitは追加/削除されたファイルを再分析し、移動済みとして正しくマークしました。


0

これを行うには、おそらくより良い「コマンドライン」の方法があり、これはハックであることは知っていますが、良い解決策を見つけることはできませんでした。

TortoiseGITの使用:GITコミットで、ファイルの変更が小さい場合でも、一部のファイル移動操作が名前の変更ではなく追加/削除の負荷として表示される場合は、次のようにします。

  1. ローカルで行ったことを確認してください
  2. 2回目のコミットで小さな一行の変更をチェックインする
  3. Tortoise gitのGITログインに移動
  4. 2つのコミットを選択して右クリックし、「1つのコミットにマージ」を選択します

新しいコミットはファイルの名前変更を正しく表示するようになりました...これは適切なファイル履歴を維持するのに役立ちます。


0

ファイルの編集、名前変更、移動を同時に行うと、これらの解決策はどれも機能しません。解決策は、2つのコミットでそれを実行し(編集および名前変更/個別に移動)fixup、2番目のコミットを介しgit rebase -iて1つのコミットでそれを実行することです。


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

1
git statusdeleted: old_file」と「Untracked files: ... new_file」と言う:Git 2.18以降ではない:stackoverflow.com/a/50573107/6309
VonC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.