764

Git でプロジェクト サブツリーの名前を変更/移動したい

/project/xyz

/components/xyz

プレーンを使用するgit mv project componentsと、のすべてのコミット履歴xyz projectが失われます。履歴が保持されるようにこれを移動する方法はありますか?

4

13 に答える 13

702

Git は、コミットで操作を永続化するのではなく、名前の変更を検出するため、使用するかどうかgit mvmv問題ではありません。

このlogコマンドは--follow、名前変更操作の前に履歴を継続する引数を取ります。つまり、ヒューリスティックを使用して同様のコンテンツを検索します。

http://git-scm.com/docs/git-log

完全な履歴を検索するには、次のコマンドを使用します。

git log --follow ./path/to/file
于 2010-02-22T22:26:14.917 に答える
113

ファイルの名前を変更して履歴をそのまま保持することは可能ですが、リポジトリの履歴全体でファイルの名前が変更されます。これはおそらく、強迫観念の git-log 愛好家のためだけのものであり、次のような深刻な影響があります。

  • 共有履歴を書き換える可能性があります。これは、Git を使用する際に最も重要な禁止事項です。他の誰かがリポジトリのクローンを作成した場合は、これを実行してリポジトリを壊します。頭痛を避けるために、クローンを再作成する必要があります。名前の変更が十分に重要な場合はこれで問題ないかもしれませんが、慎重に検討する必要があります。オープンソース コミュニティ全体を動揺させる結果になる可能性があります。
  • リポジトリ履歴の以前に古い名前を使用してファイルを参照した場合、事実上、以前のバージョンが壊れています。これを改善するには、もう少しフープ ジャンプを行う必要があります。不可能ではありませんが、退屈で、おそらく価値がありません。

さて、あなたはまだ私と一緒にいるので、おそらく完全に分離されたファイルの名前を変更する単独の開発者です。を使ってファイルを移動しようfilter-tree

ファイルoldをフォルダーに移動dirし、名前を付けるとします。new

これは で実行できますgit mv old dir/new && git add -u dir/newが、それは歴史を壊します。

その代わり:

git filter-branch --tree-filter 'if [ -f old ]; then mkdir dir && mv old dir/new; fi' HEAD

ブランチ内のすべてのコミットをやり直し、各反復のティックでコマンドを実行します。これを行うと、多くのことがうまくいかない可能性があります。私は通常、ファイルが存在するかどうかをテストして (存在しない場合は、まだ移動する必要はありません)、必要な手順を実行して、好みに合わせてツリーを押し込みます。ここでは、ファイルへの参照などを変更するためにファイルを sed することがあります。ノックアウト!:)

完了すると、ファイルは移動され、ログはそのまま残ります。あなたは忍者海賊のように感じます。

また; もちろん、mkdir dir は、ファイルを新しいフォルダーに移動する場合にのみ必要です。ifは、ファイルが存在するよりも前の履歴でこのフォルダーの作成を回避します。

于 2013-02-28T11:59:42.850 に答える
46
git log --follow [file]

名前の変更を通じて履歴が表示されます。

于 2010-02-22T22:25:05.790 に答える
24

そうです:

git mv {old} {new}
git add -u {new}
于 2012-11-24T19:07:27.490 に答える
13

「履歴を失わずにフォルダーの名前を変更する」という問題に直面しました。それを修正するには、次を実行します。

$ git mv oldfolder temp && git mv temp newfolder
$ git commit
$ git push
于 2020-06-23T09:07:41.507 に答える
9

ディレクトリまたはファイルの名前を変更するには (複雑なケースについてはよく知らないので、いくつか注意点があるかもしれません):

git filter-repo --path-rename OLD_NAME:NEW_NAME

言及しているファイル内のディレクトリの名前を変更するには (コールバックを使用することは可能ですが、方法がわかりません):

git filter-repo --replace-text expressions.txt

expressions.txtのような行で満たされたファイルですliteral:OLD_NAME==>NEW_NAME(Python の RE を使用するregex:か、 globを使用することができますglob:)。

コミットのメッセージでディレクトリの名前を変更するには:

git-filter-repo --message-callback 'return message.replace(b"OLD_NAME", b"NEW_NAME")'

Python の正規表現もサポートされていますが、Python で手動で記述する必要があります。

--forceリポジトリがリモートのないオリジナルの場合、書き換えを強制するために追加する必要があります。(これを行う前に、リポジトリのバックアップを作成することをお勧めします。)

ref を保存したくない場合 (Git GUI のブランチ履歴に表示されます)、 を追加する必要があります--replace-refs delete-no-add

于 2020-03-03T16:10:21.240 に答える
3

Git の中核である Git 配管は名前の変更を追跡しませんが、必要に応じて、Git ログ「磁器」で表示する履歴で名前を検出できます。

git log-M オプションを指定して使用します。

git ログ -p -M

現在のバージョンの Git を使用。

これは、同様に他のコマンドでgit diffも機能します。

比較を多少厳密にするオプションがあります。同時にファイルに大きな変更を加えずにファイルの名前を変更すると、Git ログや友人が名前の変更を検出しやすくなります。このため、あるコミットでファイルの名前を変更し、別のコミットで変更する人もいます。

ファイルの名前が変更された場所を見つけるように Git に要求するたびに、CPU の使用にコストがかかるため、それを使用するかどうか、いつ使用するかはあなた次第です。

特定のリポジトリで名前変更検出を使用して履歴を常に報告したい場合は、次を使用できます。

git config diff.renames 1

あるディレクトリから別のディレクトリに移動するファイル検出されます。次に例を示します。

commit c3ee8dfb01e357eba1ab18003be1490a46325992
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:20:19 2017 -0500

    test rename again

diff --git a/yyy/power.py b/zzz/power.py
similarity index 100%
rename from yyy/power.py
rename to zzz/power.py

commit ae181377154eca800832087500c258a20c95d1c3
Author: John S. Gruber <JohnSGruber@gmail.com>
Date:   Wed Feb 22 22:19:17 2017 -0500

    rename test

diff --git a/power.py b/yyy/power.py
similarity index 100%
rename from power.py
rename to yyy/power.py

これは、 だけでなく diff を使用しているときはいつでも機能することに注意してくださいgit log。例えば:

$ git diff HEAD c3ee8df
diff --git a/power.py b/zzz/power.py
similarity index 100%
rename from power.py
rename to zzz/power.py

試行として、機能ブランチの 1 つのファイルに小さな変更を加えてコミットし、マスター ブランチでファイルの名前を変更してコミットし、ファイルの別の部分に小さな変更を加えてコミットしました。機能ブランチに移動してマスターからマージすると、マージによってファイルの名前が変更され、変更がマージされました。マージからの出力は次のとおりです。

 $ git merge -v master
 Auto-merging single
 Merge made by the 'recursive' strategy.
  one => single | 4 ++++
  1 file changed, 4 insertions(+)
  rename one => single (67%)

その結果、ファイルの名前が変更され、両方のテキストが変更された作業ディレクトリが作成されました。そのため、名前の変更を明示的に追跡していなくても、Git が正しいことを行うことは可能です。

これは古い質問に対する遅い回答であるため、当時の Git バージョンでは他の回答が正しかった可能性があります。

于 2017-02-23T04:54:04.083 に答える