Wciśnij gałąź repo Gita do nowego zdalnego (github), ukrywając jego historię

Moja organizacja przygotowuje się do wydania open-source ' owej wersji naszego oprogramowania za pomocą Githuba, jednak nie jestem pewien, czy jest to najlepszy sposób na to:

Mamy dwie gałęzie master i release, master zawiera pewne zastrzeżone komponenty, których zdecydowaliśmy się nie wydawać, a release zawiera oczyszczoną wersję, którą chcemy dystrybuować. Problem w tym, że jeśli wciśniemy gałąź release do Githuba, to własnościowe komponenty można je pobrać, przeglądając historię wersji.

Rozważałem utworzenie osobnego repozytorium, skopiowanie do niego głowicy relase, Wykonanie git init i przeniesienie tego repozytorium na github. Chcemy jednak zachować możliwość wybierania pewnych łatek zmaster dorelease w przyszłości i przenosić te zmiany na github.

Czy jest sposób, aby to zrobić bez utrzymywania dwóch separate repozytoria?

Dzięki!

Aktualizacja:

Aby być bardziej szczegółowym, tak wygląda nasza historia zmian w tej chwili:

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

Gdzie 'o' są zatwierdzeniami w master , proprietary branch, 'c' są zatwierdzeniami, które usuwają rzeczy, które nie powinny być opublikowane (często nie usuwają całych plików, ale przerabiają istniejące, aby nie polegać na własnościowych komponentach), A ' f ' są poprawkami wmaster , które mają zastosowanie również do release , i tak zostały wyselekcjonowane. REL jest oznaczoną wersją kodu, którą uważamy za bezpieczną do opublikowania, bez żadnej historii (nawet poprzednie wersje gałęzi release, ponieważ nie wszystkie zastrzeżone materiały zostały usunięte przed znacznikiem rel).

Author: David Claridge, 2010-10-26

2 answers

Odpowiedź Bena Jacksona już obejmuje ogólną ideę, ale chciałbym dodać kilka uwag (więcej niż komentarz jest wart) na temat ostatecznego celu tutaj.

Możesz łatwo mieć dwie gałęzie, jedną z całkowicie czystą (bez prywatnych plików) historią, a drugą kompletną (z prywatnymi plikami) i odpowiednio udostępniać zawartość. Kluczem jest uważność na to, jak się łączysz. W 1998 roku w ramach programu "Horyzont 2020" w ramach programu "Horyzont 2020" utworzono]}

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

Commity o to " czyste" te, a x to te, które zawierają pewne prywatne informacje. Tak długo, jak łączysz się z publicznego na prywatny, oba mogą mieć wszystkie pożądane udostępnione treści, nigdy nie wyciekając niczego. Jak powiedział Ben, musisz na to uważać - nigdy nie połączysz się w drugą stronę. Mimo to jest całkiem możliwe, aby uniknąć - i nie musisz ograniczać się do cherry-picking. Możesz użyć normalnego pożądanego przepływu pracy scalania.

W rzeczywistości, twój przepływ pracy może skończyć się trochę bardziej złożone, oczywiście. Możesz stworzyć temat (feature/bugfix) na jego własnej gałęzi, a następnie połączyć go zarówno z publicznymi, jak i prywatnymi wersjami. Od czasu do czasu możesz nawet wybrać cherry-pick. Naprawdę, wszystko idzie, z wyjątkiem połączenia prywatnego z publicznym.

Filter-branch

Więc Twoim problemem jest po prostu wprowadzenie repozytorium do tego stanu. Niestety, to może być dość trudne. Zakładając, że istnieją pewne commity, które dotykają zarówno prywatnych, jak i publicznych plików, Uważam, że najprostszą metodą jest użycie filter-branch do utworzenia publicznej (czystej) wersji:

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)

Następnie utwórz tymczasową gałąź tylko prywatną, zawierającą tylko prywatną zawartość:

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

I na koniec utwórz prywatną gałąź. Jeśli nie przeszkadza Ci posiadanie tylko jednej pełnej wersji, możesz po prostu połączyć się raz: {]}

git branch private private-temp
git merge public

To da ci historię z tylko jednym scaleniem:

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

Uwaga: są tu dwa oddzielne commity roota. To trochę dziwne; jeśli aby tego uniknąć, możesz użyć git rebase --root --onto <SHA1>, aby przeszczepić całą gałąź private-temp na jakiegoś przodka gałęzi publicznej.

Jeśli chcesz mieć jakieś pośrednie pełne wersje, możesz zrobić dokładnie to samo, zatrzymując się tu i ówdzie, aby scalić i rebase:

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...

To da ci historię coś takiego:

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

Ponownie, jeśli chcesz, aby miały wspólnego przodka, możesz zrobić początkowy git rebase --root --onto ..., aby zacząć.

Uwaga: Jeśli masz scalanie już w twojej historii, będziesz chciał użyć opcji -p W Dowolnych rebasach, aby zachować scalanie.

Fake it

Edit: jeśli przeróbka historii naprawdę okaże się trudna, zawsze możesz ją całkowicie sfałszować: zmiażdżyć całą historię do jednego commita, na szczycie tego samego commita głównego, który już masz. Coś takiego:

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

Więc skończysz z tym:

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

Gdzie A i A' zawierają dokładnie tę samą treść, a X jest commit, w którym usunięto całą zawartość prywatną z gałęzi publicznej.

W tym momencie możesz wykonać pojedyncze połączenie publicznego z prywatnym, a następnie postępować zgodnie z obiegiem pracy, który opisałem u góry odpowiedzi:]}
git checkout private
git merge -s ours public

-s ours mówi gitowi, aby użył" naszej " strategii scalania. Oznacza to, że przechowuje całą zawartość dokładnie tak, jak jest w prywatnej gałęzi i po prostu rejestruje commit merge pokazujący, że połączyłeś z nią publiczną gałąź. To uniemożliwia gitowi kiedykolwiek zastosowanie tych zmian "Usuń Prywatne" z commit X do prywatnej gałęzi.

Jeśli commit główny zawiera prywatne informacje, to prawdopodobnie będziesz chciał utworzyć nowy commit główny, zamiast zatwierdzać go raz na szczycie bieżącego.

 17
Author: Cascabel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-26 12:57:38

SHA commita opiera się na obiekcie blob commit, który zawiera nadrzędny SHA, tekst commita i SHA drzewa plików. Drzewo zawiera SHA każdej plamy na drzewie. Tak więc każdy commit zależy od wszystkiego w tej rewizji i każda rewizja rodzica wraca do pustego repozytorium. Jeśli masz commit pochodzący z wersji (bez względu na to, jak pośrednio), która zawiera pliki, których nie chcesz zwolnić, nie chcesz zwolnić tej gałęzi.

The very first przykład git filter-branch mówi o usunięciu poufnego pliku z repozytorium. Robi to, tworząc alternatywną historię (przepisując wszystkie drzewa i commity). Widzisz, dlaczego to musi być prawda, jeśli rozumiesz pierwszą część mojej odpowiedzi.

Powinieneś być w stanie uruchomić polecenia filter-branch, aby utworzyć nowy commit z "czystego" commita. Historia będzie nieco dziwna(starsze wersje mogą nie budować, ponieważ są teraz niekompletne lub w inny sposób zepsute). To nie zniszczy wszystkie istniejące gałęzie lub obiekty BLOB w repozytorium. Utworzy wszystkie nowe (równoległe), które współdzielą obiekty blob plików, ale nie drzewa lub commity. Powinieneś być w stanie bezpiecznie wcisnąć tę gałąź bez ujawniania żadnych obiektów, do których się nie odnosi (kiedy naciskasz gałąź, tylko SHA nazwane przez tę gałąź i jej zależności są wypychane). Jednak byłoby to nieco ryzykowne, ponieważ jeden git merge w" czystą "gałąź i może skończyć się przeciągając w" prywatnych " gałęziach i obiektów. Możesz użyć Hooka (commit lub push trigger), aby dokładnie sprawdzić, czy prywatne pliki nie uciekają.

 5
Author: Ben Jackson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-26 04:20:28