gitでのファイル名の変更の処理


440

gitファイルの名前を変更するときは、変更をコミットし、名前を変更してから、名前を変更したファイルをステージングする必要があると読みました。Gitは、ファイルを新しい追跡されていないファイルではなく、コンテンツから認識し、変更履歴を保持します。

しかし、今夜これを行うだけで、に戻ってしまいましたgit mv

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

Finderでスタイルシートの名前をからに変更iphone.cssしますmobile.css

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   deleted:    css/iphone.css
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   css/mobile.css

したがって、gitは、CSSファイルを1つ削除して、新しいファイルを追加したと考えます。私が望むものではなく、名前の変更を元に戻してgitに処理を任せます。

> $ git reset HEAD .
Unstaged changes after reset:
M   css/iphone.css
M   index.html

私が始めたところに戻ります。

> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   index.html
#

git mv代わりに使用してみましょう。

> $ git mv css/iphone.css css/mobile.css
> $ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   renamed:    css/iphone.css -> css/mobile.css
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   index.html
#

私たちは元気です。では、Finderを使用したときに、Gitが名前の変更を初めて認識しなかったのはなぜですか?


29
Gitはファイルではなくコンテンツを追跡するため、インデックスをどのように適切な状態にするかは関係ありません。add+rmまたはmv、同じ結果が得られます。次に、Gitは名前変更/コピー検出を使用して、名前が変更されたことを通知します。あなたが引用した出典も不正確です。同じcommitで変更と名前の変更を行うかどうかは関係ありません。変更と名前変更の両方でdiffを実行すると、名前変更検出はそれを名前変更+変更として認識します。または、変更が完全な書き換えである場合は、追加および削除として表示されます-実行方法には関係ありません。それ。
Cascabel

6
これに該当する場合、Finderを使用して名前を変更しても検出されなかったのはなぜですか?
Greg K

26
git mv old newインデックスを自動的に更新します。あなたはGitリポジトリの外の名前を変更すると、あなたは何をする必要がありますgit add newし、git rm oldインデックスへの変更をステージングします。これgit statusを実行すると、期待どおりに動作します。
Chris Johnsen、2010

4
public_htmlgitで追跡されている多数のファイルをdirに移動しました。とを実行git add .したgit commit後も、「削除」された一連のファイルがまだ表示されていましたgit status。私はaを実行しgit commit -a、削除はコミットされましたが、今は、public_html現在住んでいるファイルの履歴がありません。このワークフローは、私が望むほどスムーズではありません。
グレッグK

回答:


352

以下のためのマニュアルページは 言いますgit mv

インデックスは正常に完了した後に更新されます、[…]

したがって、最初は自分でインデックスを更新する必要があります(を使用してgit add mobile.css)。ただし、
git status 2つの異なるファイルが表示されます

$ git status
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       new file:   mobile.css
#
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       deleted:    iphone.css
#

を実行すると、別の出力が得られ、 git commit --dry-run -a期待どおりの結果になります。

Tanascius@H181 /d/temp/blo (master)
$ git commit --dry-run -a
# On branch master
warning: LF will be replaced by CRLF in index.html
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       modified:   index.html
#       renamed:    iphone.css -> mobile.css
#

我々は間のこれらの違いを参照してくださいなぜ私は正確にあなたを伝えることができないgit status
git commit --dry-run -a、しかし、ここからのヒントである リーナス

gitは内部的には「名前変更の検出」全体を気にしていません。名前変更を使用して行ったコミットは、名前変更の表示に使用するヒューリスティックとは完全に独立しています。

A dry-runは実際の名前変更メカニズムを使用しますが、 git statusおそらく使用しません。


1
あなたはあなたがしたステップに言及することに失敗しましたgit add mobile.css。それgit status -aがなければ、以前に追跡されたiphone.cssファイルの削除が「見られる」だけで、追跡されていない新しいmobile.cssファイルには影響しません。また、git status -aGit 1.7.0以降では無効です。「「git status」は「git commit --dry-run」ではなくなりました。」でkernel.org/pub/software/scm/git/docs/RelNotes-1.7.0.txtgit commit --dry-run -aこの機能が必要な場合に使用します。他の人が言ったように、インデックスを更新git statusするだけで、OPが期待するように機能します。
Chris Johnsen、2010

3
通常のgit commit場合、名前が変更されたファイルはコミットされず、作業ツリーは同じままです。git commit -agitのワークフロー/思考モデルのほぼすべての側面を打ち負かします-すべての変更がコミットされます。ファイルの名前を変更するだけindex.htmlで、別のコミットで変更をコミットする場合はどうなりますか?
knittl 2010

@クリス:うん、もちろん私mobile.cssは言及すべきだったものを追加した。しかし、それは私の答えのポイントです:manページには、と言うthe index is updatedあなたが使用している場合git-mvstatus -a説明をありがとう、私はgit 1.6.4を使用しました
tanascius

4
正解です。なぜgit status名前の変更が検出されなかったのかを理解しようとして、壁に頭をぶつけていました。git commit -a --dry-run「新しい」ファイルを追加して実行すると、名前の変更が示され、最終的にコミットする自信がつきました!
stephen.hanson 2013

1
git 1.9.1ではgit status、のように動作するようになりましたgit commit
JacquesRenéMesrine、2015年

77

gitが移動として認識するには、2つの変更されたファイルをインデックスに追加する必要があります。

唯一の違いmv old newgit mv old new gitのMVが、インデックスにファイルを追加することです。

mv old new その後 git add -Aうまくいくでしょう。

あなたはただ使うことができないことに注意してください git add .インデックスに削除が追加されないため、ことはできません。

「git add -A」と「git add」の違いをご覧ください


3
このgit add -Aようなショートカットを探していたので、リンクをありがとう、非常に便利です!
PhiLho

5
git 2では、インデックスに削除git add . 追加されることに注意してください。
Nick McCurdy 14

19

自分で試してみるのが一番です。

mkdir test
cd test
git init
touch aaa.txt
git add .
git commit -a -m "New file"
mv aaa.txt bbb.txt
git add .
git status
git commit --dry-run -a

git statusとgit commit --dry-run -aが2つの異なる結果を表示するようになりました。ここで、git statusは新しいファイル/ aaa.txtが削除されたときにbbb.txtを示し、-dry-runコマンドは実際の名前変更を示します。

~/test$ git status

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   new file:   bbb.txt
#
# 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:    aaa.txt
#


/test$ git commit --dry-run -a

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   renamed:    aaa.txt -> bbb.txt
#

次に、チェックインを行います。

git commit -a -m "Rename"

これで、ファイルの名前が実際に変更され、git statusに表示されているものが間違っていることがわかります。

話の教訓:ファイルの名前が変更されたかどうかわからない場合は、「git commit --dry-run -a」を発行してください。ファイルの名前が変更されていることを示している場合は、問題ありません。


3
Gitにとって重要なことは、どちらも正しいことです。後者はコミッターがおそらくそれを見るので、あなたの方法に近いです。renameとdelete + create の本当の違いは、OS /ファイルシステムレベル(たとえば、同じiノード#と新しいiノード#)のみであり、Gitはあまり気にしません。
Alois Mahdal 14

15

git 1.7.xの場合、次のコマンドが機能しました。

git mv css/iphone.css css/mobile.css
git commit -m 'Rename folder.' 

元のファイル(つまり、css / mobile.css)はすでにコミット済みファイルにすでに含まれているため、git addは必要ありませんでした。


5
この。他のすべての答えは途方もなく不必要に複雑です。これにより、コミットとコミットの間のファイル履歴が維持されるため、ファイル名の変更前/後のマージが破損しません。
2018年

10

あなたはgit add css/mobile.css新しいファイルとを持っている必要があるgit rm css/iphone.cssので、gitはそれについて知っています。その後、同じ出力が表示されますgit status

あなたはステータス出力(ファイルの新しい名前)でそれをはっきりと見ることができます:

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

(旧名):

# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)

舞台裏git mvは、まさにそれを行うラッパースクリプトにすぎないと思います。インデックスからファイルを削除し、別の名前で追加します


git rm css/iphone.cssこれは既存の歴史を取り除くだろうと思ったので、私はそうする必要があるとは思いませんでした。たぶん私はgitのワークフローを誤解しています。
Greg K

4
@Greg K:git rm履歴は削除されません。インデックスからエントリを削除するだけなので、次のコミットにはエントリがありません。ただし、祖先のコミットには引き続き存在します。混乱するかもしれませんが、(たとえば)git log -- newコミットした時点で停止しますgit mv old new。名前の変更を追跡する場合は、を使用しますgit log --follow -- new
Chris Johnsen、2010

9

gitの観点からファイルについて考えてみましょう。

gitはファイルに関するメタデータを追跡しないことに注意してください

あなたのリポジトリは(とりわけ)を持っています

$ cd repo
$ ls
...
iphone.css
...

そしてそれはgitの制御下にあります:

$ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked
file is tracked

これをテストします:

$ touch newfile
$ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked
(no output, it is not tracked)
$ rm newfile

あなたがするとき

$ mv iphone.css mobile.css

gitの観点から、

  • iphone.cssはありませ(削除されています-gitはそれについて警告します)。
  • 新しいファイルmobile.cssがありますます。
  • これらのファイルはまったく無関係です。

だから、gitのは、それがすでに知っているファイル(約助言iphone.cssそれが検出さ)と新しいファイル(mobile.css)が、ファイルをインデックスまたはHEADのgitにある場合にのみ、その内容をチェックするために開始します。

現時点では、「iphone.css削除」もmobile.cssもインデックスにされてい。

インデックスにiphone.css削除を追加

$ git rm iphone.css

gitは何が起こったかを正確に伝えます:(iphone.cssが削除されます。それ以上は何も起こりません)

次に、新しいファイルmobile.cssを追加します

$ git add mobile.css

今回は、削除と新しいファイルの両方がインデックスに登録されています。gitはコンテキストが同じであることを検出し、名前を変更して公開します。実際、ファイルの50%が類似している場合は、それを名前変更として検出し、mobile.cssを変更できます、操作を名前の変更として保持しながら、を少し。

これはで再現可能git diffです。ファイルがインデックスに登録されたので、使用する必要があります--cachedmobile.cssを少し編集し、インデックスに追加して、次の違いを確認します。

$ git diff --cached 

そして

$ git diff --cached -M

-Mの「名前変更の検出」オプションですgit diff。(50%以上の類似性はgitが名前を変更することを-M意味します)を意味し-M50%ますが、-M20%mobile.cssを頻繁に編集する場合、これを(20%)に減らすことができます。


8

手順1:ファイルの名前をoldfileからnewfileに変更します。

git mv #oldfile #newfile

ステップ2:git commitとコメントの追加

git commit -m "rename oldfile to newfile"

ステップ3:この変更をリモートサーバーにプッシュする

git push origin #localbranch:#remotebranch

1
OPに役立つようにコメントを追加してください
Devrath

手順2は不要です。の後git mv、新しいファイルはすでにインデックスに登録されています。
Alois Mahdal、2014年

7

Gitはファイルを新しい追跡されていないファイルとしてではなく、内容から認識します

それはあなたが間違ったところです。

それだけだ後に gitのは、コンテンツからそれを認識することを、あなたはファイルを追加します。


丁度。ステージングすると、gitは名前の変更を正しく表示します。
Max MacLeod

3

ファインダームーブの結果をステージングしませんでした。Finder経由で移動してからを実行した場合git add css/mobile.css ; git rm css/iphone.css、gitは新しいファイルのハッシュを計算し、それから初めてファイルのハッシュが一致する(つまり、名前が変更される)ことに気づくと思います。


2

たとえば、手動でファイルの名前を手動で変更する必要がある場合。スクリプトを使用して一連のファイルの名前を一括で変更し、使用するとgit add -A .うまくいきました。


2

Xcodeユーザーの場合:Xcodeでファイルの名前を変更すると、バッジアイコンが追加に変わります。XCodeを使用してコミットを行うと、実際に新しいファイルが作成され、履歴が失われます。

回避策は簡単ですが、Xcodeを使用してコミットする前に行う必要があります。

  1. フォルダでgit Statusを実行します。段階的な変更が正しいことがわかります。

名前が変更されました:Project / OldName.h-> Project / NewName.h名前が変更されました:Project / OldName.m-> Project / NewName.m

  1. commit -m 'name change'

次に、XCodeに戻ると、バッジがAからMに変更されていることがわかります。これで、xcodeを使用してさらに変更をコミットすることが保存されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.