it-swarm.com.de

Machen Sie das aktuelle Commit zum einzigen (anfänglichen) Commit in einem Git-Repository?

Ich habe derzeit ein lokales Git-Repository, das ich in ein Github-Repository schiebe.

Das lokale Repository hat ~ 10 Commits und das Github-Repository ist ein synchronisiertes Duplikat.

Ich würde gerne den gesamten Versionsverlauf aus dem lokalen Git-Repository entfernen, sodass der aktuelle Inhalt des Repositorys als einziges Commit angezeigt wird (und daher ältere Versionen von Dateien im Repository nicht gespeichert werden). 

Ich möchte diese Änderungen dann zu Github verschieben.

Ich habe Git rebase untersucht, aber dies scheint besser geeignet zu sein, um bestimmte Versionen zu entfernen .. Eine andere mögliche Lösung besteht darin, das lokale Repo zu löschen und ein neues zu erstellen - obwohl dies wahrscheinlich viel Arbeit verursachen würde!

ETA: Es gibt bestimmte Verzeichnisse/Dateien, die nicht protokolliert werden. Wenn möglich, möchte ich das Entpacken dieser Dateien beibehalten.

568
kaese

Hier ist der Brute-Force-Ansatz. Es entfernt auch die Konfiguration des Repositorys.

Note: Dies funktioniert NICHT, wenn das Repository Submodule hat! Wenn Sie Submodule verwenden, sollten Sie z. interaktive Rebase

Schritt 1: Entfernen Sie den gesamten Verlauf (Stellen Sie sicher, dass Sie eine Sicherung haben; dies kann nicht wiederhergestellt werden).

cat .git/config  # note <github-uri>
rm -rf .git

Schritt 2: Rekonstruieren Sie das Git-Repo nur mit dem aktuellen Inhalt

git init
git add .
git commit -m "Initial commit"

Schritt 3: Wechseln Sie zu GitHub.

git remote add Origin <github-uri>
git Push -u --force Origin master
879
Fred Foo

Die einzige Lösung, die für mich funktioniert (und Submodule am Laufen hält) ist

git checkout --Orphan newBranch
git add -A  # Add all files and commit them
git commit
git branch -D master  # Deletes the master branch
git branch -m master  # Rename the current branch to master
git Push -f Origin master  # Force Push master branch to github
git gc --aggressive --Prune=all     # remove the old files

Das Löschen von .git/ verursacht immer große Probleme, wenn ich über Submodule verfügt. git rebase --root würde für mich irgendwie Konflikte verursachen (und es dauert lange, bis ich viel Geschichte hatte).

509
Zeelot

Dies ist mein bevorzugter Ansatz:

git branch new_branch_name $(echo "commit message" | git commit-tree HEAD^{tree})

Dadurch wird ein neuer Zweig mit einem Commit erstellt, der alles in HEAD hinzufügt. Es ändert nichts anderes und ist daher absolut sicher.

76
dan_waterworth

Die andere Option, die sich bei vielen Commits als sehr aufwendig erweisen könnte, ist eine interaktive Rebase (vorausgesetzt, Ihre Git-Version ist> = 1.7.12): git rebase --root -i

Wenn in Ihrem Editor eine Liste mit Commits angezeigt wird:

  • Ändern Sie "pick" in "umformulieren" für den ersten Commit 
  • Ändern Sie "pick" in "fixup" bei jedem zweiten Commit

Speichern und schließen. Git beginnt mit der Umbasierung. 

Am Ende haben Sie ein neues Root-Commit, das sich aus allen folgenden zusammensetzt.

Der Vorteil ist, dass Sie Ihr Repository nicht löschen müssen. Wenn Sie darüber nachdenken, haben Sie immer einen Fallback.

Wenn Sie Ihren Verlauf wirklich nuke machen möchten, setzen Sie den Master auf dieses Commit zurück und löschen Sie alle anderen Zweige.

31
Carl

Variante der vorgeschlagenen Methode von larsmans :

Speichern Sie Ihre Liste der untrackfiles:

git ls-files --others --exclude-standard > /tmp/my_untracked_files

Speichern Sie Ihre Git-Konfiguration:

mv .git/config /tmp/

Führen Sie dann die ersten Schritte von Larsmans durch:

rm -rf .git
git init
git add .

Stellen Sie Ihre Konfiguration wieder her:

mv /tmp/config .git/

Entpacken Sie nicht aufgespürte Dateien:

cat /tmp/my_untracked_files | xargs -0 git rm --cached

Dann begehen Sie:

git commit -m "Initial commit"

Und zum Schluss schieben Sie zu Ihrem Repository:

git Push -u --force Origin master
17
lalebarde

Sie könnten shallow clones (git> 1.9) verwenden:

git clone --depth depth remote-url

Weiterführende Literatur: http://blogs.atlassian.com/2014/05/handle-big-repositories-git/

5
Matthias M

Die unten beschriebene Methode ist exakt reproduzierbar. Wenn beide Seiten konsistent sind, müssen Sie das Klonen nicht erneut ausführen. Führen Sie das Skript auch auf der anderen Seite aus.

git log -n1 --format=%H >.git/info/grafts
git filter-branch -f
rm .git/info/grafts

Wenn Sie es dann bereinigen möchten, probieren Sie dieses Skript aus:

http://sam.nipl.net/b/git-gc-all-ferocious

Ich habe ein Skript geschrieben, das "Geschichte tötet" für jeden Zweig im Repository:

http://sam.nipl.net/b/git-kill-history

siehe auch: http://sam.nipl.net/b/confirm

2
Sam Watkins

git filter-branch ist das Hauptwerkzeug für die Chirurgie.

git filter-branch --parent-filter true -- @^!

--parent-filter bringt die Eltern auf stdin und sollte die umgeschriebenen Eltern auf stdout drucken; Unix true wird erfolgreich beendet und gibt nichts aus, also: keine Eltern. @^! ist Git die Abkürzung für "der Head Commit, aber keine Eltern". Dann löschen Sie alle anderen Refs und drücken Sie zur freien Verfügung.

1
jthill

Löschen Sie einfach das Github-Repo und erstellen Sie ein neues. Bei weitem der schnellste, einfachste und sicherste Ansatz. Was müssen Sie schließlich für die Ausführung all dieser Befehle in der akzeptierten Lösung erhalten, wenn Sie nur den Master-Zweig mit einem einzigen Commit wünschen?

0
AndroidDev

Nachfolgend finden Sie ein Skript, das an die Antwort von @Zeelot angepasst wurde. Es sollte die Historie von allen Zweigen entfernen, nicht nur vom Hauptzweig:

for BR in $(git branch); do   
  git checkout $BR
  git checkout --Orphan ${BR}_temp
  git commit -m "Initial commit"
  git branch -D $BR
  git branch -m $BR
done;
git gc --aggressive --Prune=all

Es hat für meine Zwecke funktioniert (ich verwende keine Submodule).

0
Shafique Jamal

Ich würde gerne den gesamten Versionsverlauf aus dem lokalen Git-Repository entfernen, sodass der aktuelle Inhalt des Repositorys als einziges Commit angezeigt wird (und daher ältere Versionen von Dateien im Repository nicht gespeichert werden). 

Eine konzeptionellere Antwort:

git sammelt bei git automatisch alte Commits, wenn keine Tags/Branchen/Refs auf sie zeigen. Sie müssen also einfach alle Tags/Verzweigungen entfernen und ein neues Orphan-Commit erstellen, das mit jeder Branch-Konvention verknüpft ist - Sie würden den Zweig master auf dieses Commit zeigen lassen.

Die alten, nicht erreichbaren Commits werden dann nie wieder von jedermann gesehen, es sei denn, sie gehen mit git-Befehlen auf niedriger Ebene. Wenn das für Sie reicht, würde ich einfach dort aufhören und den automatischen GC überlassen, wann immer er möchte. Wenn Sie sie sofort loswerden möchten, können Sie git gc (möglicherweise mit --aggressive --Prune=all) verwenden. Für das Remote-Git-Repository können Sie dies jedoch nicht erzwingen, es sei denn, Sie haben Shell-Zugriff auf ihr Dateisystem.

0
AnoE