web-dev-qa-db-ja.com

Gitでファイル名の変更を処理する

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が名前の変更を初めて認識しなかったのはなぜですか?

406
Greg K

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ですが、ここに Linus からのヒントがあります

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

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

327
tanascius

Gitが移動としてそれを認識する前に、2つの修正されたファイルをインデックスに追加しなければなりません。

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

mv old newそしてgit add -Aもうまくいったでしょう。

git add .はインデックスに削除を追加するものではないため、単に使用することはできません。

"git add -A"と "git add"の違いを参照してください。

72
nonrectangular

一番いいのは自分で試してみることです。

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

~/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"を発行してください。ファイルの名前が変更されたことが表示されたら、問題ありません。

18
dimuthu

新しいファイルとgit add css/mobile.cssgit 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はまさにそれをするラッパースクリプトに過ぎないと思います。インデックスからファイルを削除して別の名前で追加する

10
knittl

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で再現可能です。ファイルがインデックスに登録されたので、--cachedを使用する必要があります。 mobile.css を少し編集し、それをインデックスに追加して、以下の違いを確認します。

$ git diff --cached 

そして

$ git diff --cached -M

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

9
albfan

Git 1.7.xでは、以下のコマンドが役に立ちました。

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

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

9
GrigorisG

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

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

それは あと あなたがファイルを追加しただけで、そのgitは内容からそれを認識するでしょう。

7
hasen

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

git mv #oldfile #newfile

ステップ2:git commitしてコメントを追加する

git commit -m "rename oldfile to newfile"

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

git Push Origin #localbranch:#remotebranch
7
Haimei

あなたはあなたのFinder移動の結果を上演しませんでした。 Finderで移動してからgit add css/mobile.css ; git rm css/iphone.cssを実行した場合、gitは新しいファイルのハッシュを計算し、それからファイルのハッシュが一致することを認識します(したがって名前の変更です)。

3
Mike Seplowitz

あなたが本当に手動でファイルの名前を変更しなければならない場合、例えば。スクリプトを使ってたくさんのファイルの名前を一括して変更してから、git add -A .を使ってもうまくいきました。

2
pckben

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を使用する際のさらなる変更をコミットするために節約されます。

1
doozMen