web-dev-qa-db-de.com

Verschieben Sie die Datei und das Verzeichnis zusammen mit dem Festschreibungsverlauf in ein Unterverzeichnis

Wie kann ich ein Verzeichnis und Dateien zusammen mit dem Commit-Verlauf in ein Unterverzeichnis verschieben?

Beispielsweise:

  • Quellverzeichnisstruktur: [project]/x/[files & sub-dirs]

  • Zielverzeichnisstruktur: [project]/x/p/q/[files & sub-dirs]

64
rst.ptl

Um zu bmargulies 's comment hinzuzufügen, lautet die vollständige Sequenz:

mkdir -p x/p/q      # make sure the parent directories exist first
git mv x/* x/p/q    # move folder, with history preserved
git commit -m "changed the foldername x into x/p/q"

Versuchen Sie es zuerst, um eine Vorschau des Umzugs zu sehen:

git mv -n x/* x/p/q

WolfgangKommentare :

Wenn Sie bash verwenden, können Sie das Problem vermeiden, einen Ordner in sich selbst zu verschieben, indem Sie einen erweiterten Glob wie folgt verwenden (mit dem integrierten shopt ):

shopt -s extglob; git mv !(folder) folder

Captain Man berichtet in den Kommentaren muss machen:

mkdir temp 
git mv x/* temp
mkdir -p x/p/q
git mv temp x/p/q
rmdir temp;

Kontext:

Ich bin mit Cygwin auf Windows.
Mir ist gerade aufgefallen, dass ich den shopt -s extglob Beispiel falsch, so dass mein Weg möglicherweise nicht notwendig ist, aber ich verwende normalerweise zsh anstelle von bash, und es hatte nicht den Befehl shopt -s extglob (obwohl ich mir sicher bin, dass es eine Alternative gibt), daher sollte dieser Ansatz für alle Shells funktionieren (Subbing in den mkdir und rmdir Ihrer Shell, wenn es besonders fremd ist)


Als Alternative erwähnt spankyin den Kommentaren das -k Option von git mv :

Überspringen Sie Verschiebungs- oder Umbenennungsaktionen, die zu einem Fehler führen würden.

git mv -k * target/

Das würde das "can not move directory into itself" Error.

63
VonC

Git macht einen sehr guten Job, um Inhalte zu verfolgen, auch wenn sie verschoben werden, also git mv ist eindeutig der richtige Weg, wenn Sie Dateien verschieben, weil sie früher zu x gehörten, jetzt aber zu x/p/q weil sich das projekt so entwickelt hat.

Manchmal gibt es jedoch einen Grund, Dateien im Verlauf eines Projekts in ein Unterverzeichnis zu verschieben. Zum Beispiel, wenn die Dateien versehentlich irgendwo abgelegt wurden und seitdem einige weitere Commits durchgeführt wurden, die intermittierenden Commits jedoch nicht einmal Sinn ergeben, wenn sich die Dateien an der falschen Stelle befinden. Wenn all das in einer lokalen Niederlassung passiert ist, möchten wir das Durcheinander bereinigen, bevor wir es verschieben.

In der Frage steht "zusammen mit der Commit-Geschichte", was ich so interpretieren würde, als würde ich die Geschichte auf genau diese Weise umschreiben. Dies kann mit erfolgen

git filter-branch --tree-filter "cd x; mkdir -p p/q; mv [files & sub-dirs] p/q" HEAD

Die Dateien erscheinen dann im p/q Unterverzeichnis im Verlauf.

Bitte beachten Sie, dass das Ergebnis nicht auf einen öffentlichen Server übertragen werden sollte, wenn das Umschreiben bereits übertragene Commits berührt.

40
PiQuer

Ich kann sehen, dass dies eine alte Frage ist, aber ich fühle mich dennoch verpflichtet, mit meiner gegenwärtigen Lösung des Problems zu antworten, die ich aus einem der Beispiele im Git-Buch abgeleitet habe. Anstatt ein ineffizientes --tree-filter Ich verschiebe die Dateien direkt im Index Mit einem --index-filter.

git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/^<old_location>/<new_location>/"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

dies ist eine Spezialisierung eines der Beispiele aus dem Buch. Ich habe dasselbe Beispiel auch verwendet, um Dateien im Festschreibungsverlauf in einem speziellen Fall massenweise umzubenennen. Wenn Sie Dateien in Unterverzeichnissen verschieben: Denken Sie daran, das Zeichen/in den Pfaden mit einem\zu maskieren, damit der Befehl sed wie erwartet funktioniert.

Beispiel:

Project Directory
                 |-a
                 |  |-a1.txt
                 |  |-b
                 |  |  |-b1.txt

so verschieben Sie das Verzeichnis b in das Projektstammverzeichnis:

git filter-branch -f --index-filter 'PATHS=`git ls-files -s | sed "s/a\/b\//b\//"`;GIT_INDEX_FILE=$GIT_INDEX_FILE.new; echo -n "$PATHS" | git update-index --index-info && if [ -e "$GIT_INDEX_FILE.new" ]; then mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"; fi' -- --all

Ergebnis:

Project Directory
                 |-a
                 |  |-a1.txt
                 |
                 |-b
                 |  |-b1.txt
9
peroyhav

Der Befehl git mv ist der einfachste Weg. Zumindest auf meiner Linux-Box musste ich jedoch das -k-Flag angeben, um zu vermeiden, dass ein Fehler zurückgegeben wird, dass ein Ordner nicht in sich selbst verschoben werden kann. Ich konnte die Aktion ausführen, indem ich ...

mkdir subdirectory
git mv -k ./* ./subdirectory
# check to make sure everything moved (see below)
git commit

Als Warnung überspringt dies alle Bewegungen, was zu einer Fehlerbedingung führen würde. Daher sollten Sie wahrscheinlich überprüfen, ob nach dem Verschieben und vor einem Festschreiben alles ordnungsgemäß funktioniert hat.

6
Jeremy Hutchins