Behandlung von Dateien in git umbenennen

Ich würde lesen, dass beim Umbenennen von Dateien in Git , sollten Sie alle Änderungen festschreiben , führen Sie Ihre Umbenennung und dann Ihre umbenannte Datei. Git erkennt die Datei aus dem Inhalt, anstatt sie als neue nicht aufgezeichnete Datei zu sehen und behält den Änderungsverlauf bei.

Aber gerade heute Abend bin ich zu git mv .

 > $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: index.html # 

Benennen Sie mein Stylesheet im Finder von iphone.css in mobile.css

 > $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: index.html # # Changed but not updated: # (use "git add/rm ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # deleted: css/iphone.css # # Untracked files: # (use "git add ..." to include in what will be committed) # # css/mobile.css 

Git denkt jetzt, ich habe eine CSS-Datei gelöscht und eine neue hinzugefügt. Nicht was ich will, lässt die Umbenennung rückgängig machen und lass git die Arbeit machen.

 > $ git reset HEAD . Unstaged changes after reset: M css/iphone.css M index.html 

Zurück zu dem, wo ich angefangen habe.

 > $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: index.html # 

Lass git mv stattdessen git mv benutzen.

 > $ git mv css/iphone.css css/mobile.css > $ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # renamed: css/iphone.css -> css/mobile.css # # Changed but not updated: # (use "git add ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # modified: index.html # 

Sieht so aus, als wären wir gut. Also, warum habe ich das Umbenennen beim ersten Mal nicht erkannt, als ich den Finder benutzt habe?

Für git mv sagt die Handbuchseite

Der Index wird nach erfolgreichem Abschluss aktualisiert, [….]

Zuerst müssen Sie den Index selbst aktualisieren (indem Sie git add mobile.css ). jedoch
git status zeigt immer noch zwei verschiedene Dateien an

 $ git status # On branch master warning: LF will be replaced by CRLF in index.html # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # modified: index.html # new file: mobile.css # # Changed but not updated: # (use "git add/rm ..." to update what will be committed) # (use "git checkout -- ..." to discard changes in working directory) # # deleted: iphone.css # 

Sie können eine andere Ausgabe erhalten, indem Sie git commit --dry-run -a was zu dem führt, was Sie erwarten

 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 ..." to unstage) # # modified: index.html # renamed: iphone.css -> mobile.css # 

Ich kann dir nicht genau sagen, warum wir diese Unterschiede zwischen git status und
git commit --dry-run -a , aber hier ist ein Hinweis von Linus

git kümmert sich wirklich nicht einmal um die gesamte “Umbenennungserkennung”, und alle Commits, die Sie mit Umbenennungen gemacht haben, sind völlig unabhängig von den Heuristiken, die wir dann verwenden, um die Umbenennungen anzuzeigen.

Ein dry-run verwendet die echten Umbenennungsmechanismen, während ein git status wahrscheinlich nicht tut.

Sie müssen die zwei geänderten Dateien zum Index hinzufügen, bevor git sie als Verschiebung erkennt.

Der einzige Unterschied zwischen mv old new und git mv old new ist, dass der git mv auch die Dateien zum Index hinzufügt.

mv old new dann git add -A hätte auch funktioniert.

Beachten Sie, dass Sie nicht einfach git add . weil das dem Index keine Entfernungen hinzufügt.

Siehe Unterschiede zwischen “git add -A” und “git add”.

Das beste ist, es selbst zu versuchen.

 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 und git commit –dry-run -a zeigt zwei verschiedene Ergebnisse, wobei git status bbb.txt anzeigt, wenn eine neue Datei / aaa.txt gelöscht wird, und die –dry-run-Befehle die tatsächliche Umbenennung anzeigen.

 ~/test$ git status # On branch master # Changes to be committed: # (use "git reset HEAD ..." to unstage) # # new file: bbb.txt # # Changes not staged for commit: # (use "git add/rm ..." to update what will be committed) # (use "git checkout -- ..." 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 ..." to unstage) # # renamed: aaa.txt -> bbb.txt # 

Jetzt gehen Sie voran und machen Sie den Check-in.

 git commit -a -m "Rename" 

Jetzt können Sie sehen, dass die Datei tatsächlich umbenannt wurde und was im Git-Status angezeigt wird, ist falsch.

Moral der Geschichte: Wenn Sie nicht sicher sind, ob Ihre Datei umbenannt wurde, geben Sie eine “git commit – dry-run -a” aus. Wenn es anzeigt, dass die Datei umbenannt wurde, ist es gut zu gehen.

du musst git add css/mobile.css die neue datei und git rm css/iphone.css , also weiß git davon. dann wird es die gleiche Ausgabe im git status

Sie können es deutlich in der Statusausgabe (der neue Name der Datei) sehen:

 # Untracked files: # (use "git add ..." to include in what will be committed) 

und (der alte Name):

 # Changed but not updated: # (use "git add/rm ..." to update what will be committed) 

Ich denke, hinter den Kulissen git mv ist nichts anderes als ein Wrapper-Skript, das genau das tut: Lösche die Datei aus dem Index und füge sie unter einem anderen Namen hinzu

Lass uns über deine Dateien aus der Gitperspektive nachdenken.

Denken Sie daran, dass git keine Metadaten zu Ihren Dateien verfolgt

Ihr Repository hat (unter anderem)

 $ cd repo $ ls ... iphone.css ... 

und es ist unter Git Kontrolle:

 $ git ls-files --error-unmatch iphone.css &>/dev/null && echo file is tracked file is tracked 

Testen Sie dies mit:

 $ touch newfile $ git ls-files --error-unmatch newfile &>/dev/null && echo file is tracked (no output, it is not tracked) $ rm newfile 

Wenn Sie das tun

 $ mv iphone.css mobile.css 

Aus der Git Perspektive,

  • es gibt keine iphone.css (es ist gelöscht -git warnt davor-).
  • Es gibt eine neue Datei mobile.css .
  • Diese Dateien sind völlig unabhängig voneinander.

Also rät git über Dateien, die es bereits kennt ( iphone.css ) und neue Dateien, die es erkennt ( mobile.css ), aber nur wenn Dateien im Index sind oder HEAD git beginnt, ihren Inhalt zu überprüfen.

In diesem Moment befinden sich weder “iphone.css deletion” noch mobile.css auf dem Index.

Fügen Sie iphone.css zum Index hinzu

 $ git rm iphone.css 

git sagt dir genau, was passiert ist: ( iphone.css ist gelöscht. Es ist nichts mehr passiert)

Fügen Sie dann die neue Datei mobile.css hinzu

 $ git add mobile.css 

Diesmal sind sowohl das Löschen als auch die neue Datei im Index. Jetzt entdeckt Git den Kontext und stellt es als Umbenennung dar. In der Tat, wenn Dateien 50% ähnlich sind, wird es erkennen, dass als eine Umbenennung, Sie können mobile.css ein wenig ändern, während die Operation als Umbenennung beibehalten .

Siehe das ist reproduzierbar auf git diff . Jetzt, da sich Ihre Dateien im Index befinden, müssen Sie --cached . Bearbeiten Sie mobile.css ein wenig, fügen Sie das zum Index hinzu und sehen Sie den Unterschied zwischen:

 $ git diff --cached 

und

 $ git diff --cached -M 

-M ist die Option “detect renames” für git diff . -M steht für -M50% (50% oder mehr Ähnlichkeit macht git es als Umbenennung express), aber Sie können dies auf -M20% (20%) reduzieren, wenn Sie mobile.css viel bearbeiten.

Git wird die Datei aus dem Inhalt erkennen, anstatt sie als neue nicht aufgezeichnete Datei zu sehen

Da bist du falsch gelaufen.

Erst nachdem du die Datei hinzugefügt hast, wird sie vom Inhalt erkannt.

Schritt 1: Benenne die Datei von “Oldfile” in “Newfile” um

 git mv #oldfile #newfile 

Schritt 2: git commit und Kommentare hinzufügen

 git commit -m "rename oldfile to newfile" 

Schritt 3: Drücken Sie diese Änderung auf Remote-Server

 git push origin #localbranch:#remotebranch 

Für Git 1.7.x funktionierten folgende Befehle für mich:

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

Git add war nicht nötig, da die Originaldatei (zB css / mobile.css) bereits zuvor in den Commit-Dateien enthalten war.

Du hast die Ergebnisse deines Finderzuges nicht inszeniert. Ich glaube, wenn Sie den Umzug über Finder getan haben und dann git add css/mobile.css ; git rm css/iphone.css git add css/mobile.css ; git rm css/iphone.css , git würde den Hash der neuen Datei berechnen und erst dann erkennen, dass die Hashes der Dateien übereinstimmen (und damit ein Umbenennen).

In Fällen, in denen Sie die Dateien wirklich manuell umbenennen müssen, z. Verwenden Sie ein Skript, um Stapel von Dateien umzubenennen, und verwenden Sie dann git add -A . hat für mich gearbeitet.

Für Xcode-Benutzer: Wenn Sie Ihre Datei in Xcode umbenennen, sehen Sie, dass sich das Badge-Symbol zum Anhängen ändert. Wenn Sie einen Commit mit XCode durchführen, werden Sie tatsächlich eine neue Datei erstellen und den Verlauf verlieren.

Eine Problemumgehung ist einfach, aber Sie müssen es tun, bevor Sie mit Xcode arbeiten:

  1. Führen Sie einen git-Status für Ihren Ordner aus. Sie sollten sehen, dass die gestaffelten Änderungen korrekt sind:

umbenannt: Projekt / AlterName.h -> Projekt / NeuerName.h umbenannt: Projekt / AlterName.m -> Projekt / NeuerName.m

  1. commit -m ‘Namensänderung’

Dann gehen Sie zurück zu XCode und Sie werden sehen, dass sich das Abzeichen von A nach M geändert hat und es ist sicher, weitere Änderungen in der Verwendung von xcode jetzt vorzunehmen.