Git でプロジェクト サブツリーの名前を変更/移動したい
/project/xyz
に
/components/xyz
プレーンを使用するgit mv project components
と、のすべてのコミット履歴xyz project
が失われます。履歴が保持されるようにこれを移動する方法はありますか?
Git は、コミットで操作を永続化するのではなく、名前の変更を検出するため、使用するかどうかgit mv
はmv
問題ではありません。
このlog
コマンドは--follow
、名前変更操作の前に履歴を継続する引数を取ります。つまり、ヒューリスティックを使用して同様のコンテンツを検索します。
http://git-scm.com/docs/git-log
完全な履歴を検索するには、次のコマンドを使用します。
git log --follow ./path/to/file
ファイルの名前を変更して履歴をそのまま保持することは可能ですが、リポジトリの履歴全体でファイルの名前が変更されます。これはおそらく、強迫観念の git-log 愛好家のためだけのものであり、次のような深刻な影響があります。
さて、あなたはまだ私と一緒にいるので、おそらく完全に分離されたファイルの名前を変更する単独の開発者です。を使ってファイルを移動しよう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は、ファイルが存在するよりも前の履歴でこのフォルダーの作成を回避します。
git log --follow [file]
名前の変更を通じて履歴が表示されます。
そうです:
git mv {old} {new}
git add -u {new}
「履歴を失わずにフォルダーの名前を変更する」という問題に直面しました。それを修正するには、次を実行します。
$ git mv oldfolder temp && git mv temp newfolder
$ git commit
$ git push
ディレクトリまたはファイルの名前を変更するには (複雑なケースについてはよく知らないので、いくつか注意点があるかもしれません):
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
。
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 バージョンでは他の回答が正しかった可能性があります。