2010-06-30 4 views
20

Ich erhielt einen Quellcode und entschied mich dafür, Git zu verwenden, da mein Kollege den mkdir $VERSION Ansatz verwendete. Während die Vergangenheit des Codes momentan unwichtig erscheint, würde ich es trotzdem gerne unter die Kontrolle des Gitters stellen, um den Entwicklungsprozess besser zu verstehen. Also:Wie wird die Vergangenheit einem Git-Repository vorangestellt?

Was ist eine bequeme Möglichkeit, diese früheren Versionen in meine bereits bestehende Git Repo zu setzen? Es gibt derzeit kein Remote-Repo, so dass es mir nichts ausmacht, den Verlauf neu zu schreiben, aber eine Lösung, die Remote-Repositories berücksichtigt, wird natürlich bevorzugt, es sei denn, sie ist dann viel komplizierter. Bonuspunkte für ein Skript, das keine weitere Interaktion mehr benötigt, basierend auf einem Verzeichnis- oder Archivdatei-basierten Verlauf.

+1

Siehe auch [Bearbeiten/Ändern/Ändern/Ändern der ersten/root/initial commit in Git?] (Http://stackoverflow.com/q/2119480/456814), [Ändern der ersten Commit des Projekts mit Git?] (http://StackOverflow.com/Q/2246208/456814), und [Git: Wie füge ich Commits vor dem ersten/initialen/root-Commit hinzu?] (http://StackOverflow.com/q/16762160/456814). –

+0

@Cupcake Danke, ich sah nie die Benachrichtigung für Ihre Links –

Antwort

21

Zum Importieren der alten Snapshots finden Sie einige der Tools in Git's contrib/fast-import directory nützlich. Oder, wenn Sie sich bereits alte Schnappschuss in einem Verzeichnis haben, können Sie etwas tun:

# Assumes the v* glob will sort in the right order 
# (i.e. zero padded, fixed width numeric fields) 
# For v1, v2, v10, v11, ... you might try: 
#  v{1..23}  (1 through 23) 
#  v?{,?}  (v+one character, then v+two characters) 
#  v?{,?{,?}} (v+{one,two,three} characters) 
#  $(ls -v v*) (GNU ls has "version sorting") 
# Or, just list them directly: ``for d in foo bar baz quux; do'' 
(git init import) 
for d in v*; do 
    if mv import/.git "$d/"; then 
     (cd "$d" && git add --all && git commit -m"pre-Git snapshot $d") 
     mv "$d/.git" import/ 
    fi 
done 
(cd import && git checkout HEAD -- .) 

Dann die alte Geschichte in Ihre Arbeits Repository holen:

cd work && git fetch ../import master:old-history 

Einmal Wenn Sie sowohl die alte Historie als auch Ihre Git-basierte Historie im selben Repository haben, haben Sie eine Reihe von Optionen für die Vorbereitungsoperation: Grafts und Ersetzungen.

Grafts sind ein pro-Repository-Mechanismus, um die Herkunft verschiedener existierender Commits (möglicherweise vorübergehend) zu bearbeiten. Transplantate werden von der Datei $GIT_DIR/info/grafts gesteuert (beschrieben unter "info/grafts" der gitrepository-layout manpage).

INITIAL_SHA1=$(git rev-list --reverse master | head -1) 
TIP_OF_OLD_HISTORY_SHA1=$(git rev-parse old-history) 
echo $INITIAL_SHA1 $TIP_OF_OLD_HISTORY_SHA1 >> .git/info/grafts 

Mit dem Transplantat an Ort und Stelle (der ursprüngliche Anfang begangen hat keine Eltern hat, gab das Transplantat es einen Elternteil), können Sie all normalen Git-Tools verwenden, um durch die Suche und die erweiterte Geschichte sehen (zB git log sollte dir nun die alte Geschichte nach deinen Commits zeigen).

Das Hauptproblem bei Transplantaten ist, dass sie auf Ihr Repository beschränkt sind. Aber, wenn Sie entscheiden, dass sie ein fester Bestandteil der Geschichte sein sollten, können Sie git filter-branch verwenden, um sie so zu machen (machen Sie eine tar/zip-Sicherung von Ihrem .git dir zuerst; git filter-branch wird gespeichert Originalreferenzen, aber manchmal ist es einfacher, ein einfaches Backup zu verwenden).

git filter-branch --tag-name-filter cat -- --all 
rm .git/info/grafts 

Der Ersatz-Mechanismus ist neuer (Git 1.6.5 +), aber sie können auf einer Pro-Befehl-Basis (git --no-replace-objects …) und sie können zum leichteren Austausch geschoben deaktiviert werden. Replacement arbeitet an einzelnen Objekten (Blobs, Trees, Commits oder Annotated Tags), also ist der Mechanismus auch allgemeiner. Der Austauschmechanismus ist in der git replace manpage dokumentiert. Aufgrund der Allgemeinheit, (haben wir die neue Mutter Namensgebung ein neuer begehen, anstatt nur erstellen) die „Prepending“ Setup ein wenig mehr beteiligt ist:

# the last commit of old history branch 
oldhead=$(git rev-parse --verify old-history) 
# the initial commit of current branch 
newinit=$(git rev-list master | tail -n 1) 
# create a fake commit based on $newinit, but with a parent 
# (note: at this point, $oldhead must be a full commit ID) 
newfake=$(git cat-file commit "$newinit" \ 
     | sed "/^tree [0-9a-f]\+\$/aparent $oldhead" \ 
     | git hash-object -t commit -w --stdin) 
# replace the initial commit with the fake one 
git replace -f "$newinit" "$newfake" 

Freigabe dieser Ersatz ist nicht automatisch.Sie müssen einen Teil von (oder allen) refs/replace drücken, um den Ersatz zu teilen.

git push some-remote 'refs/replace/*' 

Wenn Sie sich entscheiden, die Ersetzung dauerhaft zu machen, verwenden Sie git filter-branch (wie bei Transplantationen; eine tar/zip Sicherung Ihrer .git Verzeichnis machen zuerst):

git filter-branch --tag-name-filter cat -- --all 
git replace -d $INITIAL_SHA1 
+0

Danke, das funktioniert gut für eine kleine Test-Teilmenge, jetzt auf die komplette :) (Ich habe die Ersatz-Option) –

+0

Dies ist kein Problem für mich bei der Moment, aber ich werde trotzdem fragen: Die Replace-Option bis zum Punkt vor 'git filter-branch' zu verwenden, schreibt den Verlauf nicht neu und ist daher leichter zu teilen, oder? –

+2

Ohne * git filter branch * schreiben weder Grafts noch Ersetzungen den Verlauf neu (sie wirken sich nur auf die Commit-DAG aus, als hätten sie die Historie neu geschrieben). Die Vorteile von Ersetzungen sind 1) sie können durch Befehlszeilenargument oder Umgebungsvariable deaktiviert werden, 2) sie können pushed/geholt werden, 3) sie arbeiten an jedem Objekt, nicht nur an den übergeordneten "attritubes" von commits. Die Fähigkeit, Ersetzungen zu erzwingen, macht es einfach, sie über die normalen Git-Protokolle zu teilen (Sie können Graft-Einträge teilen, aber Sie müssen einen "Out-of-Band" -Mechanismus verwenden (d. H. Nicht push/fetch), um sie zu propagieren). –

1

Der einfachste Ansatz besteht natürlich darin, ein neues Git Repo zu erstellen, indem man die Historie festlegt, bevor man die Patches des alten Repos anwendet. Aber ich bevorzuge eine Lösung, die durch Automatisierung weniger zeitaufwendig ist.

2

Wenn Wenn Sie die Commits in Ihrem Repository nicht ändern möchten, können Sie mithilfe der Grafts die übergeordneten Informationen für ein Commit überschreiben. Dies ist, was der Linux-Kernel-Repo tut, um den Verlauf zu erhalten, bevor sie Git benutzen.

Diese Nachricht: http://marc.info/?l=git&m=119636089519572 scheint die beste Dokumentation zu haben, die ich finden kann.

Sie würden eine Sequenz von Commits in Bezug auf Ihren Pre-Git-Verlauf erstellen und dann die Datei .git/info/grafts verwenden, damit Git das letzte Commit in dieser Sequenz als Parent des ersten Commits verwendet, das Sie mit Git generiert haben.

+1

+1 ah ja, ich sehe, danke. Dies ist detailliert als die Transplantation-Option in [Chris Johnsens Antwort] (http://stackoverflow.com/questions/3147097/how-to-prepend-the-past-to-a-git-repository/3148117#3148117) –

Verwandte Themen