[解決済み] git mv` とは対照的に、git コピーファイル
質問
gitはファイルの中身を差分することで機能すると理解しています。私はコピーしたいファイルがあります。gitが混乱するのを絶対に防ぐために、ファイルを別のディレクトリにコピーして(mvではなく、cp)、同様にファイルをステージするために使用できるgitコマンドはあるのでしょうか?
解決方法は?
簡単に言うと、「ノー」です。 しかし、もっと知るべきことがあり、それにはいくつかの背景が必要です。 (そして
JDBがコメントで提案
の理由についても触れておきます。
git mv
は便宜上存在します)。
少し長くなりますが、Git がファイルの diff を取るというのは正しいのですが、以下の点については間違っているかもしれません。 いつ Git はこのファイル差分を実行します。
Gitの内部ストレージ・モデルは、各コミットが
すべて
は、そのコミット内のファイルです。 新しいコミットに含まれる各ファイルのバージョン、つまりそのパスのスナップショット内のデータは、そのパスのインデックスで
git commit
.
1
実際の実装は、最初のレベルでは、各スナップショット・ファイルを圧縮した形で取り込み ブロブオブジェクト を Git データベースに保存します。 この blob オブジェクトは、そのファイルのすべての前バージョンおよび後バージョンから完全に独立しています。ただし、ひとつだけ特別なケースがあります。 いいえ のデータが変更された場合 古いブロブを再利用する . つまり、2つのコミットを連続して行い、それぞれが100のファイルを保持し、1つのファイルだけが変更された場合、2番目のコミットは99の以前のブロブを再利用し、実際のファイル1つを新しいブロブにスナップショットするだけでいいのです。 2
したがって、Gitがファイルの差分を取るという事実は、コミットを行う際には全く関係ありません。 前のコミットに依存するコミットはありません。前のコミットのハッシュIDを保存すること以外には(そしておそらく完全にマッチするブロブを再利用することですが、これは正確にマッチすることによる副作用であり、むしろ、あなたが
git commit
).
さて、このように独立したブロブオブジェクトは、最終的には法外なスペースを占有することになります。
この時点で
Gitは、オブジェクトを
.pack
ファイルを作成します。 各オブジェクトを、選択された他のオブジェクトのセットと比較します。それらは歴史的に前か後か、同じファイル名か異なるファイル名か、理論的にはGitはコミットオブジェクトをblobオブジェクトに対して圧縮することもでき、その逆もできます(実際にはそうしませんが)-そしてより少ないディスクスペースで多くのblobを表現する方法を見つけようと努力します。 しかしその結果は、少なくとも論理的にはまだ一連の独立したオブジェクトであり、ハッシュIDを使用して元の形式で完全にそのまま取得されます。 つまり、この時点で使用するディスク容量が減少しても(そうであってほしい!)、すべてのオブジェクトは以前とまったく同じものなのです。
では、いつ
が行います。
Git はファイルを比較するのでしょうか? 答えはこうです。
あなたが頼んだときだけです。
を実行したときです。
git diff
のどちらか、または直接。
git diff commit1 commit2
または間接的に
git show commit # roughly, `git diff commit^@ commmit`
git log -p # runs `git show commit`, more or less, on each commit
これについては、特に微妙な点がたくさんあります。
git show
は、Git が呼ぶところの
複合差分
をマージコミットに対して実行した場合、一方
git log -p
通常、マージコミットでは差分をスキップするだけですが、これらのケースやその他の重要なケースで Git は
git diff
.
それは
Git が実行するとき
git diff
を使えば、コピーを見つけるか見つけないかを尋ねることができます (場合によっては)。 そのため
-C
というフラグもあります。
--find-copies=<number>
は、Git にコピーを見つけるよう依頼します。 その
--find-copies-harder
フラグ (Git のドキュメントでは "computationally expensive" と呼んでいます) は、プレーンな
-C
フラグを使用します。 このフラグは
-B
(不適切なペアを解除する)オプションは
-C
. そのため
-M
別名
--find-renames=<number>
オプションは
-C
. また
git merge
コマンドはリネーム検出のレベルを調整することができますが、少なくとも現在のところ、コピーを見つけたり、不適切なペアを解除したりすることはできません。
(コマンドは1つです。
git blame
はやや異なるコピーファインディングを行うので、上記は完全に当てはまりません)。
1
を実行すると
git commit --include <paths>
または
git commit --only <paths>
または
git commit <paths>
または
git commit -a
を実行する前にインデックスを変更することだと考えてください。
git commit
. の特殊なケースでは
--only
の場合、Git は一時的なインデックスを使うので少し複雑ですが、それでもコミットは
an
インデックスの代わりに特別な一時的なものを使うだけです。 一時的なインデックスを作成するために、Gitはすべてのファイルを
HEAD
コミットし、その上に
--only
を追加しました。 その他のケースでは、Git はワークツリー・ファイルを通常のインデックスにコピーし、インデックスから通常通りコミットを実行します。
2
実際にスナップショットを行い、Blobをリポジトリに格納するのは、以下の手順で行います。
git add
. このため、密かに
git commit
を実行するのにかかる余分な時間には通常気づかないので、より高速になります。
git add
を起動する前に
git commit
.
なぜ
git mv
が存在する
何
git mv old new
が行うのは
非常に
大まかには
mv old new
git add new
git add old
最初のステップは、ワークツリー版のファイルの名前を変更することです。 2番目のステップも同様で、インデックスバージョンのファイルを所定の位置に配置する必要があります。 しかし、3つ目は
奇妙な
削除したばかりのファイルをなぜ追加しなければならないのでしょうか? まあね。
git add
は、常にファイルを追加するわけではありません。この場合、ファイル
でした。
がインデックスに含まれていて、もう存在しない。
また、その3番目のステップを次のように綴ることもできます。
git rm --cached old
私たちが実際に行っているのは、インデックスから古い名前を取り除くことだけです。
しかし、ここで問題があって、"と言ったわけです。
非常に
roughly"です。 インデックスには各ファイルのコピーがあり、次回実行時にコミットされます
git commit
.
そのコピーは、ワークツリー内のものと一致しないかもしれません。
にあるものとさえ一致しないかもしれません。
HEAD
にある場合は
HEAD
を全く使用しない。
例えば、その後。
echo I am a foo > foo
git add foo
ファイル
foo
はワークツリーにもインデックスにも存在する。 ワークツリーの内容とインデックスの内容は一致しています。 しかし、ここでワークツリーのバージョンを変更してみよう。
echo I am a bar > foo
さて、インデックスとワークツリーは異なります。 例えば、基礎となるファイルを
foo
から
bar
しかし、なぜか
3
-をしたいのです。
インデックスの内容を変更しない
. 実行すると
mv foo bar
git add bar
を取得します。
I am a bar
を新しいインデックスファイルの中に入れてください。 次に、古いバージョンの
foo
をインデックスから削除すると
I am a foo
のバージョンを完全に削除します。
だから
git mv foo bar
は、実際には移動と追加を2回行うわけでも、移動と追加と削除を行うわけでもない。 その代わり、ワークツリーファイルの名前を変更する。
と
はインデックス内コピーの名前を変更します。 元ファイルのインデックスコピーがワークツリーファイルと異なる場合、名前を変更したインデックスコピーは名前を変更したワークツリーコピーと依然として異なります。
のようなフロントエンドのコマンドがないと、とても難しいです。
git mv
.
4
もちろん、もしあなたが
git add
のすべてが必要かというと、そもそもこんなものは必要ない。 そして、注目すべきは、もし
git cp
が存在する場合、それはおそらく
また
は、インデックスのコピー時に、ワークツリーのバージョンではなく、インデックスのバージョンをコピーします。 そこで
git cp
は本当に存在するはずです。 また
git mv --after
オプションは、Mercurial の
hg mv --after
. どちらも
べきである
が存在するが、現在は存在しない。 (しかし、これらのどちらかが必要とされることは、まっすぐな
git mv
私の意見では、)
3
この例では、ちょっとバカバカしくて意味がないですね。 しかし、もしあなたが
git add -p
を使用して慎重に中間コミット用のパッチを準備し、そのパッチと一緒にファイル名を変更することにした場合、慎重にパッチした中間バージョンを混乱させることなくそれを実行できるのは間違いなく便利なことです。
4
不可能ではない
git ls-index --stage
は、今のインデックスから必要な情報を得ることができますし
git update-index
を使えば、インデックスを任意に変更することができます。 この二つと、複雑なシェルスクリプトやより優れた言語によるプログラミングを組み合わせることで、以下のような実装が可能になります。
git mv --after
と
git cp
.
関連
-
[解決済み] Git で直近のローカルコミットを取り消すには?
-
[解決済み] Gitブランチをローカルやリモートで削除するには?
-
[解決済み] git pull」と「git fetch」の違いは何ですか?
-
[解決済み] コミット前に 'git add' を取り消すにはどうすればよいですか?
-
[解決済み] リモートのGitブランチをチェックアウトするには?
-
[解決済み] Git のリモートブランチを作成する方法を教えてください。
-
[解決済み] コミットに含まれるすべてのファイルを一覧表示するにはどうすればよいですか?
-
[解決済み] Git リポジトリを特定のフォルダにクローンする方法は?
-
[解決済み】"git pull" でローカルファイルを強制的に上書きするには?
-
[解決済み】ローカルのGitブランチの名前を変更するには?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] git pull リモートブランチがリモートの参照先を見つけることができない
-
[解決済み】Githubの認証に失敗した - ... GitHubはシェルアクセスを提供しない
-
[解決済み】「オリジン/マスターへのプッシュが拒否されました」というエラーが常に発生するのはなぜですか?
-
[解決済み] [Solved] 作業ツリーのディレクトリ 'example.com' を作成できませんでした。パーミッションが拒否されました
-
[解決済み] git が「Pull is not possible because you have unmerged files」と表示するのはなぜですか?
-
[解決済み] 複数のコミットをチェリーピックする方法
-
[解決済み] fatal: bad revision "とはどういう意味ですか?
-
[解決済み] ssh-keygen' は内部コマンドまたは外部コマンドとして認識されません。
-
[解決済み】Gitのコピーファイルで履歴を残す【重複
-
[解決済み] Gitによるファイルコピー操作の記録