477

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

4

14 に答える 14

370

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 -aLinusからのヒントを次に示します。

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

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

于 2010-04-14T21:35:39.857 に答える
88

Gitがそれを移動として認識する前に、2つの変更されたファイルをインデックスに追加する必要があります。

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

mv old newそうすれば、それgit add -Aもうまくいったでしょう。

git add .インデックスに削除が追加されないため、を使用することはできないことに注意してください。

「gitadd-A」と「gitadd」の違いを参照してください。

于 2011-10-21T07:18:07.280 に答える
34

Git 1.7.xの場合、次のコマンドが機能しました。

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

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

于 2015-07-08T22:36:17.303 に答える
19

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

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

~/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実装では、2つのコマンドが別々に扱われる場合があります。

話の教訓:ファイルの名前が変更されたかどうかわからない場合は、「gitcommit--dry-run-a」を発行してください。ファイルの名前が変更されていることが示されている場合は、問題ありません。

于 2014-04-01T06:07:40.763 に答える
13

ステップ1:ファイルの名前をoldfileからnewfileに変更します

git mv #oldfile #newfile

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

git commit -m "rename oldfile to newfile"

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

git push origin #localbranch:#remotebranch
于 2014-05-27T18:29:47.850 に答える
10

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

于 2010-04-14T21:34:55.613 に答える
9

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

$ git diff --cached

$ git diff --cached -M

-Mの「名前の変更を検出」オプションですgit diff-M-M50%(50%以上の類似性により、Gitは名前変更として表現します)を表しますが、ファイルmobile.css-M20%を頻繁に編集する場合は、これを(20%)に減らすことができます。

于 2015-02-10T21:16:09.233 に答える
8

Gitは、ファイルを新しい追跡されていないファイルとして表示するのではなく、コンテンツからファイルを認識します

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

ファイルを追加して初めて、Gitはコンテンツからファイルを認識します。

于 2010-04-15T00:29:11.963 に答える
3

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

于 2010-04-14T21:37:13.647 に答える
2

たとえば、スクリプトを使用して一連のファイルの名前を一括変更してから、を使用してファイルの名前を手動で変更する必要がある場合は、うまくいきgit add -A .ました。

于 2012-05-02T11:31:29.410 に答える
2

Xcodeユーザーの場合:Xcodeでファイルの名前を変更している場合は、バッジアイコンが変更されて追加されます。Xcodeを使用してコミットを行うと、実際に新しいファイルが作成され、履歴が失われます。

回避策は簡単ですが、Xcodeを使用してコミットする前に回避する必要があります。

  1. フォルダでGitステータスを実行します。段階的な変更が正しいことを確認する必要があります。

    renamed:    Project/OldName.h -> Project/NewName.h
    renamed:    Project/OldName.m -> Project/NewName.m
    
  2. 行うcommit -m 'name change'

    次にXcodeに戻ると、バッジがAからMに変更され、Xcodeを使用する際の将来の変更をコミットするために保存されます。

于 2012-08-17T07:47:27.387 に答える
1

この問題が発生しただけです。大量のファイルを更新し、それらすべてを実行したくない場合は、git mvこれも機能します。

  1. 親ディレクトリの名前をから/dir/RenamedFile.jsに変更し/whatever/RenamedFile.jsます。
  2. git add -Aその変化を上演する
  3. 親ディレクトリの名前をに戻し/dir/RenamedFile.jsます。
  4. git add -A繰り返しますが、その変更に対して再ステージングし、gitにファイル名の変更を取得させます。
于 2020-12-14T19:58:14.227 に答える
1

ウィンドウ10のgit2.33でテスト済み

  1. Explorerで必要なフォルダとファイルの名前を変更します。
  2. git add .
  3. git commit -m "commit message"
  4. git push

Gitは名前の変更を検出します。実行して確認できますgit status(コミット後)

ここに画像の説明を入力してください

于 2021-11-19T16:02:56.073 に答える
0

フォルダとファイルを大文字にしたとき、Node.jsのファイルシステムを使用してこの問題を解決しました。

始める前にコミットすることを忘れないでください。どれだけ安定しているかわかりません:)

  1. プロジェクトルートにスクリプトファイルを作成します。
// File rename.js

const fs = require('fs').promises;
const util = require('util');
const exec = util.promisify(require('child_process').exec);

const args = process.argv.slice(2);
const path = args[0];

const isCapitalized = (s) => s.charAt(0) === s.charAt(0).toUpperCase();

const capitalize = (s) => s.charAt(0).toUpperCase() + s.slice(1);

async function rename(p) {
  const files = await fs.readdir(p, { withFileTypes: true });
  files.forEach(async (file) => {
    const { name } = file;
    const newName = capitalize(name);
    const oldPath = `${p}/${name}`;
    const dumbPath = `${p}/dumb`;
    const newPath = `${p}/${newName}`;
    if (!isCapitalized(name) && name !== 'i18n' && name !== 'README.md') {
      // 'git mv' won't work if we only changed size of letters.
      // That's why we need to rename to dumb name first, then back to current.
      await exec(`git mv ${oldPath} ${dumbPath}`);
      await exec(`git mv ${dumbPath} ${newPath}`);
    }
    if (file.isDirectory()) {
      rename(newPath);
    }
  });
}

rename(path);

ディレクトリ(または単一ファイル)内のすべてのファイルの名前を変更するには、スクリプトを使用する方が簡単です。

// rename.js

const fs = require('fs').promises;
const util = require('util');
const exec = util.promisify(require('child_process').exec);
const args = process.argv.slice(2);
const path = args[0];

async function rename(p) {
  const files = await fs.readdir(p, { withFileTypes: true });
  files.forEach(async (file) => {
    const { name } = file;
    const currentPath = `${p}/${name}`;
    const dumbPapth = `${p}/dumb`;
    await exec(`git mv ${currentPath} ${dumbPath}`);
    await exec(`git mv ${dumbPath} ${currentPath}`);
    if (file.isDirectory()) {
      rename(newPath);
    }
  });
}

rename(path);
  1. 引数を指定してスクリプトを実行する
node rename.js ./frontend/apollo/queries

Node.jsを使用してシェルスクリプトファイルまたはコマンドを実行する方法

于 2020-02-27T08:09:13.343 に答える