git-mvの目的は何ですか?


287

私が理解していることから、Gitはファイルの名前変更/移動/コピー操作を実際に追跡する必要がないので、git mvの本当の目的は何ですか?マニュアルページは特に説明的ではありません...

時代遅れですか?これは内部コマンドであり、通常のユーザーが使用するためのものではありませんか?

回答:


390
git mv oldname newname

以下の略記です:

mv oldname newname
git add newname
git rm oldname

つまり、古いパスと新しいパスの両方のインデックスを自動的に更新します。


38
またそれは、いくつかの安全装置が組み込まれています。
ヤクブNarębski

6
ありがとう@CharlesBailey-gitはファイルnewNameFileとoldNameFileを異なるものと見なしますか?はいの場合、それらをマージしたい場合はどうなりますか?antプロジェクトをブランチAにブランチし、ブランチBを作成して、Bでプロジェクトをmavenizeするとします。ファイル名は同じですが、プロジェクト構造が変更されると、異なるパスに配置されます。両方のブランチが並行してしばらくの間成長したとしましょう。ある時点でプロジェクトをマージしたい場合、gitはパスの名前を変更したばかりの同じファイルであることをどうやって知るのでしょうか?( "git mv" == "git add + git rm"の場合)
Rose

2
@SergeyOrshanskiy自動検出がで失敗した場合mv oldname newname; git add newname; git rm oldname、それも失敗しますgit mv oldname newnameこの回答を参照)。
Ajedi32 2014年

5
git mvは少し異なることに注意してください。mv oldname newname; git add newname; git rm oldnameファイルを変更する前にファイルに変更を加えたgit mv場合、それらの変更はgit add新しいファイルが作成されるまでステージングされません。
Ajedi32 2014年

2
git mvは、ファイル名の大文字小文字の変更(foo.txtからFoo.txt)を処理するため、別のことをしていますが、これらのコマンドは個別に実行されません(OSXでは)
greg.kindel

66

公式GitFaqから:

Gitには名前変更コマンドがgit mvありますが、これは便利です。この効果は、ファイルを削除して、名前が同じで内容が同じである別のファイルを追加することと区別がつかない


8
それでは、ファイル履歴を失いますか?名前を変更すると、そのディレクトリの古い履歴が保持されると思いました...
Will Hancock

17
はい、そうです。名前の変更に関する上記のGitFaq公式リンクを読んでから、Linus TorvaldsがSCMツールトラッキングファイルの概念を好まない理由についての長い電子メールを読んでください:permalink.gmane.org/gmane.comp.version-control.git/ 217
アダムノフシンガー2013年

3
@WillHancock私はもう少しgitを使用しており、より明確に答えることができます:gitクライアントとそのオプションに応じて、ファイルが内部でわずかに変更され、それを考慮している場合、ファイルの名前を変更して過去のファイルを追跡できます。名前を変更します。ファイルを変更しすぎて名前を変更しても、gitはそれを検出しません-ある意味では、「いいえ、まったく別のファイルと見なすこともできます!」
Adam Nofsinger 2015年

7
@AdamNofsingerそのリンクは死んでいる。これがミラーです:web.archive.org/web/20150209075907/http
カールウォルシュ

2
git mvと手動のアプローチとの間の同等性を説明する公式のリファレンス(つまり、FAQよりも推力に値する)はありますか?からは明らかではありませんgit help mv
2017

40

Gitは、あなたが何をしようとしているのかを推測しようとしています。それは、壊れていない歴史を保存しようとするあらゆる試みをしています。もちろん、完璧ではありません。そのgit mvため、意図を明示し、いくつかのエラーを回避できます。

この例を考えてみましょう。空のリポジトリから始めて、

git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
mv a c
mv b a
git status

結果:

# On branch master
# 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)
#
#   modified:   a
#   deleted:    b
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   c
no changes added to commit (use "git add" and/or "git commit -a")

自動検出に失敗しました :(またはそれをしましたか?

$ git add *
$ git commit -m "change"
$ git log c

commit 0c5425be1121c20cc45df04734398dfbac689c39
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:24:56 2013 -0400

    change

その後

$ git log --follow c

Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:24:56 2013 -0400

    change

commit 50c2a4604a27be2a1f4b95399d5e0f96c3dbf70a
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:24:45 2013 -0400

    initial commit

ここで代わりに試してください(.git実験するときは必ずフォルダを削除してください)。

git init
echo "First" >a
echo "Second" >b
git add *
git commit -m "initial commit"
git mv a c
git status

ここまでは順調ですね:

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


git mv b a
git status

今、誰も完璧ではありません:

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#   modified:   a
#   deleted:    b
#   new file:   c
#

本当に?しかし、もちろん...

git add *
git commit -m "change"
git log c
git log --follow c

...結果は上記と同じ--followです。完全な履歴のみが表示されます。


どちらのオプションでも奇妙な効果が生じる可能性があるため、名前の変更には注意してください。例:

git init
echo "First" >a
git add a
git commit -m "initial a"
echo "Second" >b
git add b
git commit -m "initial b"

git mv a c
git commit -m "first move"
git mv b a
git commit -m "second move"

git log --follow a

commit 81b80f5690deec1864ebff294f875980216a059d
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:35:58 2013 -0400

    second move

commit f284fba9dc8455295b1abdaae9cc6ee941b66e7f
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:34:54 2013 -0400

    initial b

それと比較してください:

git init
echo "First" >a
git add a
git commit -m "initial a"
echo "Second" >b
git add b
git commit -m "initial b"

git mv a c
git mv b a
git commit -m "both moves at the same time"

git log --follow a

結果:

commit 84bf29b01f32ea6b746857e0d8401654c4413ecd
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:37:13 2013 -0400

    both moves at the same time

commit ec0de3c5358758ffda462913f6e6294731400455
Author: Sergey Orshanskiy <*****@gmail.com>
Date:   Sat Oct 12 00:36:52 2013 -0400

    initial a

UPSは...今、歴史はに戻って起こっている初期の代わりに、初期B間違っています、。したがって、一度に2つの動作を実行すると、Gitが混乱し、変更を適切に追跡できなくなりました。ちなみに、私の実験では、を使用する代わりにファイルを削除/作成したときにも同じことが起こりましたgit mv。注意して続行してください。あなたは警告されました...


5
詳しい説明は+1。ファイルをgitで移動した場合にログ履歴で発生する可能性がある問題を探していましたが、あなたの答えは非常に興味深いものでした。ありがとうございました!ところで、gitでファイルを移動するときに避けなければならない他の落とし穴を知っていますか?(または、あなたが指すことができる任意の参照....それについてはあまり幸運ではないグーグルではありません)
パブランテス2014年

1
まあ、私の例は悲観的です。ファイルが空の場合、変更を適切に解釈することははるかに困難です。名前変更のすべてのセットの後にコミットするだけであれば、問題ないはずです。
osa

27

@Charlesが言うように、git mvは省略形です。

ここでの本当の質問は、「他のバージョン管理システム(SubversionやPerforceなど)はファイル名の変更を特別に扱います。なぜGitを使わないのですか?」です。

Linusはhttp://permalink.gmane.org/gmane.comp.version-control.git/217で特徴的なタクトについて説明しています:

この「トラックファイル」のがらくたを停止してください。Gitは重要なもの、つまり「ファイルのコレクション」を正確に追跡します。他には何も関係がなく、それが関係があると考えていても、 あなたの世界観を制限するだけです。CVSの「注釈」の概念が常に人々の使用方法を常に制限してしまうことに注意してください。私はそれは全く役に立たないがらくたの一部であると思います、そして私が百万倍より有用であると思う何かを説明しました、そして私が私の考えを世界の間違ったモデルに限定しないのでそれはすべて正確に落ちました 。


9

git mv上で言及されていない別の使い方があります。

git add -p(git addのパッチモード。http://git-scm.com/docs/git-addを参照)を発見したので、それを使用して、インデックスに追加した変更を確認します。したがって、私のワークフローは、(1)コードの作業、(2)レビューとインデックスへの追加、(3)コミットになります。

どのgit mvように適合しますか?ファイルを直接移動してgit rmからとを使用するとgit add、すべての変更がインデックスに追加され、変更を表示するためのgit diffの使用は(コミットする前に)簡単ではなくなります。git mvただし、を使用すると、インデックスに新しいパスが追加されますが、ファイルに加えられた変更は追加されないため、git diffおよびgit add -pは通常どおり機能します。


5

git mv非常に便利なニッチなケースがあります。大文字と小文字を区別しないファイルシステムでファイル名の大文字と小文字を変更したい場合です。APFS(mac)とNTFS(windows)は、デフォルトで大文字と小文字を区別しません(ただし、大文字と小文字を区別します)。

greg.kindelは、CBベイリーの回答に対するコメントでこれについて言及しています。

Macで作業していて、Mytest.txtgitで管理されているファイルがあるとします。ファイル名をに変更しますMyTest.txt

あなたは試すことができます:

$ mv Mytest.txt MyTest.txt
overwrite MyTest.txt? (y/n [n]) y
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

まあ。Gitは、ファイルに変更があったことを認めません。

あなたは可能性があり、それをバックリネーム後、完全にファイルの名前を変更してでこの問題を回避します:

$ mv Mytest.txt temp.txt
$ git rm Mytest.txt
rm 'Mytest.txt'
$ mv temp.txt MyTest.txt
$ git add MyTest.txt 
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    Mytest.txt -> MyTest.txt

ばんざーい!

または、次のコマンドを使用することで、すべての問題を回避できますgit mv

$ git mv Mytest.txt MyTest.txt
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

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