19 Stimmen

Einen Zweig eines Git-Repositoriums in ein neues Remote-Repositorium (Github) verschieben, wobei seine Geschichte verborgen wird

Meine Organisation bereitet sich darauf vor, eine Open-Source-Version unserer Software über github zu veröffentlichen, aber ich bin mir nicht sicher, wie ich das am besten angehen soll:

Wir haben zwei Zweige Meister y freigeben , Meister enthält einige geschützte Komponenten, die wir nicht freigeben wollen, und freigeben enthält die bereinigte Version, die wir verbreiten wollen. Das Problem ist, dass wir, wenn wir nur die freigeben Zweig auf github, können die proprietären Komponenten durch einen Blick in die Revisionshistorie gefunden werden.

Ich habe überlegt, ein separates Repository zu erstellen und den HEAD von neu laden in sie hinein, indem sie eine git init und dieses Repository auf Github zu veröffentlichen. Wir möchten jedoch weiterhin die Möglichkeit haben, bestimmte Patches aus Meister en freigeben und diese Änderungen auf Github hochladen.

Gibt es eine Möglichkeit, dies zu tun, ohne zwei getrennte Repositories zu unterhalten?

Gracias.

Aktualisierung:

Um ein wenig genauer zu sein, sieht unser Commit-Verlauf im Moment ungefähr so aus:

--- o - o - o - o - f - o - o - f - master
             \
              c - c - c - c - c - c - c - REL - f - f

Wobei 'o' Commits in der Meister c' sind Übertragungen, die Dinge entfernen, die nicht veröffentlicht werden sollten (oft werden nicht ganze Dateien entfernt, sondern bestehende überarbeitet, so dass sie nicht auf proprietären Komponenten beruhen), und f' sind Korrekturen in Meister die gelten für freigeben und wurden daher herausgepickt. REL ist eine getaggte Version des Codes, den wir für sicher halten, um ihn zu veröffentlichen, ohne jegliche Vorgeschichte (auch frühere Versionen des Release-Zweigs, da nicht alles proprietäre Material vor dem REL-Tag entfernt wurde).

17voto

Cascabel Punkte 449595

Ben Jacksons Antwort deckt bereits die allgemeine Idee ab, aber ich möchte ein paar Anmerkungen (mehr als einen Kommentar wert) über das letztendliche Ziel hinzufügen.

Sie können ganz einfach zwei Zweige haben, einen mit einem völlig sauberen Verlauf (ohne private Dateien) und einen vollständigen (mit den privaten Dateien), und den Inhalt entsprechend teilen. Der Schlüssel dazu ist, dass Sie sorgfältig darauf achten, wie Sie zusammenführen. Ein vereinfachter Verlauf könnte etwa so aussehen:

o - o - o - o - o - o - o (public)
 \       \           \   \
  x ----- x ----x---- x - x (private)

El o Übertragungen sind die "sauberen", und die x sind diejenigen, die einige private Informationen enthalten. Solange Sie von öffentlich auf privat zusammenführen, können beide alle gewünschten gemeinsamen Inhalte haben, ohne dass jemals etwas durchsickert. Wie Ben schon sagte, muss man dabei vorsichtig sein - man kann nie in die andere Richtung fusionieren. Dennoch ist es durchaus möglich, dies zu vermeiden - und Sie müssen sich nicht auf die Rosinenpickerei beschränken. Sie können Ihren normalen gewünschten Zusammenführungs-Workflow verwenden.

In der Realität könnte Ihr Arbeitsablauf natürlich etwas komplexer sein. Sie könnten ein Thema (Feature/Bugfix) in einem eigenen Zweig entwickeln und es dann sowohl in die öffentliche als auch in die private Version einfließen lassen. Sie könnten sogar ab und zu eine Auswahl treffen. Wirklich alles ist möglich, mit der Ausnahme, dass die private Version in die öffentliche Version überführt wird.

filtern-verzweigen

Ihr Problem besteht also im Moment einfach darin, Ihr Repository in diesen Zustand zu bringen. Leider kann das ziemlich schwierig sein. Unter der Annahme, dass einige Commits existieren, die sowohl private als auch öffentliche Dateien berühren, glaube ich, dass die einfachste Methode darin besteht, Folgendes zu verwenden filter-branch um die öffentliche (saubere) Version zu erstellen:

git branch public master   # create the public branch from current master
git filter-branch --tree-filter ... -- public    # filter it (remove private files with a tree filter)

erstellen Sie dann einen temporären, privaten Zweig, der nur den privaten Inhalt enthält:

git branch private-temp master
git filter-branch --tree-filter ... -- private-temp    # remove public files

Und schließlich erstellen Sie den privaten Zweig. Wenn Sie damit einverstanden sind, nur eine vollständige Version zu haben, können Sie sie einfach einmal zusammenführen:

git branch private private-temp
git merge public

So erhalten Sie eine Geschichte mit nur einer Verschmelzung:

o - o - o - o - o - o - o - o - o - o (public)
                                     \
  x -- x -- x -- x -- x -- x -- x --- x (private)

Hinweis: Es gibt hier zwei separate Root-Commits. Das ist ein wenig seltsam; wenn Sie das vermeiden wollen, können Sie git rebase --root --onto <SHA1> um den gesamten privat-temp-Zweig auf einen Vorgänger des öffentlichen Zweigs zu verpflanzen.

Wenn Sie einige vollständige Zwischenversionen haben möchten, können Sie genau dasselbe tun, nur hier und da anhalten, um sie zusammenzuführen und neu zu basen:

git checkout -b private <private-SHA1>  # use the SHA1 of the first ancestor of private-temp
                                        # you want to merge something from public into
git merge <public-SHA1>           # merge a corresponding commit of the public branch
git rebase private private-temp   # rebase private-temp to include the merge
git checkout private
git merge <private-SHA1>          # use the next SHA1 on private-temp you want to merge into
                                  # this is a fast-forward merge
git merge <public-SHA1>           # merge something from public
git rebase private private-temp   # and so on and so on...

Damit erhalten Sie einen Verlauf in etwa wie folgt:

o - o - o - o - o - o - o - o - o - o (public)
      \              \               \
  x -- x -- x -- x -- x -- x -- x --- x (private)

Auch hier können Sie, wenn Sie möchten, dass sie einen gemeinsamen Vorfahren haben, eine erste git rebase --root --onto ... um loszulegen.

Hinweis: Wenn Sie bereits Zusammenführungen in Ihrem Verlauf haben, sollten Sie die Option -p Option bei allen Rebases, um die Zusammenführungen zu erhalten.

so tun, als ob

Edit: Wenn sich die Überarbeitung der Historie wirklich als schwierig erweist, können Sie es auch ganz einfach machen: Drücken Sie die gesamte Historie auf einen Commit zusammen, zusätzlich zu demselben Root-Commit, den Sie bereits haben. Etwas wie dies:

git checkout public
git reset --soft <root SHA1>
git commit

Das Ergebnis ist also Folgendes:

o - A' (public)
 \
  o - x - o - x - X - A (public@{1}, the previous position of public)
               \
                x - x (private)

donde A y A' genau den gleichen Inhalt haben und X ist die Übergabe, bei der Sie alle privaten Inhalte aus dem öffentlichen Zweig entfernt haben.

An diesem Punkt können Sie eine einmalige Zusammenführung von öffentlich und privat durchführen und von da an den Arbeitsablauf befolgen, den ich oben in der Antwort beschrieben habe:

git checkout private
git merge -s ours public

El -s ours weist git an, die Merge-Strategie "ours" zu verwenden. Das bedeutet, dass es alle Inhalte genau so beibehält, wie sie im privaten Zweig sind, und lediglich einen Merge-Commit aufzeichnet, der anzeigt, dass Sie den öffentlichen Zweig mit diesem zusammengeführt haben. Dadurch wird verhindert, dass Git jemals die "remove private"-Änderungen aus dem Commit X an die Privatwirtschaft.

Wenn der Root-Commit private Informationen enthält, sollten Sie einen neuen Root-Commit erstellen, anstatt den aktuellen Commit einmal zu überschreiben.

5voto

Ben Jackson Punkte 84305

Der SHA eines Commits basiert auf dem Commit-Blob, der den übergeordneten SHA, den Commit-Text und den SHA des Dateibaums enthält. Der Baum enthält die SHA von jedem Blob im Baum. Somit hängt jede Übergabe von allem in dieser Revision und jeder übergeordneten Revision ab, bis hin zu einem leeren Repository. Wenn Sie einen Commit haben, der von einer Version abgeleitet ist (egal wie indirekt), die Dateien enthält, die Sie nicht freigeben wollen, dann sollten Sie diesen Zweig nicht freigeben.

Das allererste Beispiel für git filter-branch behandelt das Entfernen einer vertraulichen Datei aus einem Repository. Dazu wird eine alternative Geschichte erstellt (alle Bäume und Übertragungen werden neu geschrieben). Wenn Sie den ersten Teil meiner Antwort verstanden haben, können Sie sehen, warum dies wahr sein muss.

Sie sollten in der Lage sein, die filter-branch-Befehle auszuführen, um einen neuen Commit aus Ihrem "sauberen" Commit zu erstellen. Die Historie wird etwas seltsam sein (ältere Versionen können nicht gebaut werden, weil sie jetzt unvollständig oder anderweitig kaputt sind). Dies wird keine bestehenden Zweige oder Blobs in Ihrem Repository zerstören. Es werden alle neuen (parallelen) Blobs erstellt, die die Dateiblobs, aber nicht die Bäume oder Commits teilen. Sie sollten in der Lage sein, diesen Zweig sicher zu verschieben, ohne eines der Objekte freizugeben, auf die er sich nicht bezieht (wenn Sie einen Zweig verschieben, werden nur die SHA, die von diesem Zweig und seinen Abhängigkeiten genannt werden, verschoben). Dies wäre jedoch etwas riskant, da ein git merge in den "sauberen" Zweig und Sie könnten "private" Zweige und Objekte mit hineinziehen. Sie können einen Hook (Commit- oder Push-Trigger) verwenden, um zu überprüfen, dass private Dateien nicht entkommen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X