Перенесите ветку git-репо на новый пульт (github), скрывая его историю - PullRequest
19 голосов
/ 26 октября 2010

Моя организация готовит к выпуску версию нашего программного обеспечения с открытым исходным кодом, используя github, однако я не уверен, что лучший способ подойти к этому:

У нас есть две ветви master и release , master содержит некоторые проприетарные компоненты, которые мы решили не выпускать, а release содержит очищенную версию, которую мы хотим распространять.Проблема в том, что если мы просто нажмем ветку release на github, проприетарные компоненты можно будет получить, просмотрев историю изменений.

Я думал о создании отдельного репозитория с копированием HEADиз вставьте в него, сделав git init и отправив этот репозиторий в github.Тем не менее, мы хотим сохранить возможность выбора определенных патчей из master в release в будущем и перенести эти изменения в github.

Есть лиспособ сделать это без поддержки двух отдельных репозиториев?

Спасибо!

Обновление:

Чтобы быть немного более конкретным, это как бы выглядит наша история коммитовкак на данный момент:

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

Где 'o' - коммиты в проприетарной ветке master , 'c' - коммиты, которые удаляют вещи, которые не должны публиковаться (часто не удаляютсяцелые файлы, но переработанные существующие, чтобы не полагаться на проприетарные компоненты), и 'f' - это исправления в master , которые также применяются к release , и поэтому были выбраны черри.REL - это версия кода с тегами, которую мы считаем безопасным для публикации, без какой-либо истории (даже с предыдущими версиями ветки релиза, поскольку не все проприетарные материалы были удалены до тега REL).

Ответы [ 2 ]

17 голосов
/ 26 октября 2010

Ответ Бена Джексона уже охватывает общую идею, но я хотел бы добавить несколько заметок (больше, чем ценность комментария) о конечной цели здесь.

Вы можете довольно легко иметь две ветви, однус полностью чистой (без личных файлов) историей и одной полной (с личными файлами) и соответствующим образом обмениваться контентом.Ключ должен быть осторожен в том, как вы сливаетесь.Упрощенная история может выглядеть примерно так:

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

Коммиты o являются "чистыми", а x - коммитами, содержащими некоторую личную информацию.Пока вы сливаетесь из общего в частное, они оба могут иметь весь желаемый общий контент, не пропуская ничего.Как сказал Бен, вам нужно быть осторожным с этим - вы никогда не сможете слиться иначе.Тем не менее, этого вполне можно избежать - и вам не нужно ограничивать себя сбором вишни.Вы можете использовать свой обычный желаемый рабочий процесс слияния.

В действительности, ваш рабочий процесс может оказаться немного более сложным, конечно.Вы можете разработать тему (feature / bugfix) в отдельной ветке, а затем объединить ее как с публичной, так и с приватной версиями.Вы могли бы даже выбрать вишню сейчас и потом.На самом деле все идет, за исключением ключевого исключения слияния частного в публичное.

filter-branch

Итак, ваша проблема сейчас заключается в том, чтобы просто перевести ваш репозиторий в это состояние.К сожалению, это может быть довольно сложно.Предполагая, что существуют некоторые коммиты, которые затрагивают как приватные, так и публичные файлы, я считаю, что самый простой способ - использовать filter-branch для создания публичной (чистой) версии:

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)

, а затем создать временный приватныйветка, содержащая только приватный контент:

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

И наконец, создайте приватную ветку.Если вам подходит только одна полная версия, вы можете просто выполнить слияние один раз:

git branch private private-temp
git merge public

Это даст вам историю только с одним слиянием:

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

Примечание:Здесь есть две отдельные корневые коммиты.Это немного странно;если вы хотите избежать этого, вы можете использовать git rebase --root --onto <SHA1> для трансплантации всей ветки private-temp некоторому предку публичной ветки.

Если вы хотите иметь несколько промежуточных полных версий, вы можете сделатьточно то же самое, просто остановившись здесь и там, чтобы объединить и перебазировать:

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

Это даст вам историю примерно так:

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

Опять же, если вы хотите, чтобы онииметь общего предка, вы можете сделать начальную git rebase --root --onto ..., чтобы начать.

Примечание: если у вас уже есть слияния в вашей истории, вы захотите использовать опцию -p для любых возвратов, чтобы сохранитьслияния.

подделка

Редактировать: Если переделка истории действительно оказывается неразрешимой, вы всегда можете полностью ее обмануть: раздавить всю историю до одного коммита, поверхтот же корневой коммит у вас уже есть.Примерно так:

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

Итак, в итоге вы получите:

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

, где A и A' содержат абсолютно одинаковое содержимое, а X - этофиксация, при которой вы удалили весь закрытый контент из общедоступной ветви.

На этом этапе вы можете выполнить одно слияние публичного с частным, и с этого момента следовать рабочему процессу, который я описал в верхней частиответ:

git checkout private
git merge -s ours public

-s ours говорит git использовать "нашу" стратегию слияния.Это означает, что он сохраняет весь контент в точности как в частной ветви и просто записывает коммит слияния, показывающий, что вы слили в него публичную ветку.Это препятствует тому, чтобы git применял эти «удалить личные» изменения из коммита X к частной ветви.

Если корневой коммит содержит личную информацию, то вы, вероятно, захотите создать новый корневой коммитвместо фиксации один раз поверх текущего.

5 голосов
/ 26 октября 2010

SHA коммита основан на BLOB-коммите, который включает родительский SHA, текст коммита и SHA дерева файлов.Дерево содержит SHA каждого шарика в дереве.Таким образом, любая конкретная фиксация зависит от всего в этой ревизии и каждой родительской ревизии обратно в пустой репозиторий.Если у вас есть коммит, полученный из версии (независимо от того, как косвенно), которая включает файлы, которые вы не хотите выпускать, то вы не хотите выпускать эту ветвь.

Самый первый пример git filter-branch говорит об удалении конфиденциального файла из хранилища.Это делается путем создания альтернативной истории (переписывания всех деревьев и фиксации).Вы можете понять, почему это должно быть правдой, если вы понимаете первую часть моего ответа.

Вы должны быть в состоянии выполнить команды filter-branch для создания нового коммита из вашего "чистого" коммита.История будет несколько странной (старые версии могут не скомпилироваться, потому что теперь они неполные или иным образом повреждены).Это не уничтожит ни одну из ваших существующих веток или блобов в вашем хранилище.Он создаст все новые (параллельные), которые совместно используют файловые объекты, но не деревья или коммиты.Вы должны быть в состоянии безопасно протолкнуть эту ветвь, не открывая ни один из объектов, на которые она не ссылается (когда вы нажимаете ветвь, только SHA, названный этой ветвью и ее зависимостями, выдвигается).Тем не менее, это было бы несколько рискованно, потому что один git merge в «чистую» ветку, и вы можете в конечном итоге перетаскивать в «частные» ветви и объекты.Возможно, вы захотите использовать перехват (фиксацию или запуск) для двойной проверки того, что личные файлы не экранируются.

...