Как я могу создать чистый, но связанный Git-репозиторий для общего пользования? - PullRequest
2 голосов
/ 22 мая 2019

Я работал с коллегой, чтобы привести в порядок некоторый код, который был написан некоторое время назад. Это все в Github-хранилище (частном), и есть много ветвей и фиксирующих запись длинного перехода от одного уродливого скрипта Python со спагетти-кодом в гораздо более модульную, тестируемую конструкцию.

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

Я хотел бы иметь возможность создать новый репозиторий, который просто содержит версии выпуска кода. Я хочу, чтобы между этими двумя репозиториями поддерживались ссылки, чтобы я мог затем перейти к более поздним версиям кода по мере его разработки. Есть ли простой способ добиться этого, чтобы история из репо1 не перетекла в репо2?

В виде ASCII-искусства я хочу получить два репозитория, которые выглядят так:

repo1 (private)

A -- B -- C -- D -- H -- I -- J
      \         \
       E ------- F -- G


repo2 (public)

X -- G

так, что ветви в repo1 и repo2, которые ссылаются на G, остаются связанными.

Обратите внимание, что A и X отличаются, потому что частное репо началось с массивного, уродливого сценария, которому никто никогда не должен подвергаться, а публичное репо начинается с README, лицензии и * 1015. * файл.

Если я ссылаюсь на repo2 как на удаленный от repo1, я могу протолкнуть ветвь, указывающую на G, но она возвращает всю ветвь полностью обратно к A, что не то, что я хочу. Я думаю , что мне нужно подтолкнуть X к репо1, а затем создать там ветку, в которую я могу слить G и отодвинуться назад, но мне не удалось найти ничего, описывающего такого рода операция, и я сомневаюсь, что «неподключенный» узел может быть представлен в графе Git. Есть ли способ добиться того, что мне нужно, кроме простого копирования файлов из repo1 в совершенно отдельный repo2?

Ответы [ 2 ]

1 голос
/ 22 мая 2019

Глядя на вашу диаграмму

repo1 (private)

A -- B -- C -- D -- H -- I -- J
      \         \
       E ------- F -- G


repo2 (public)

X -- G

Единственный коммит, который когда-либо может быть родителем G, это F, потому что идентификация коммита - это хеш данных коммита, который включает в себя «кто мой родитель». Вы могли бы получить

x -- G'

но тогда ветви не останутся связанными так, как вы хотите.

Одним из решений является использование мелких клонов. Что-то вроде

git clone --single-branch master --depth=1

даст вам

(F) -- G

означает "G знает, что F является его родителем, но ни F, ни его история не присутствуют в этом клоне.

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

Тем не менее, способ заставить это работать - создать ветку (public или что-то) в вашем личном репо, и каждый раз, когда вы собираетесь добавить релиз (и только тогда) объединить (с --no-ff) в эту ветку. Затем каждый раз, когда вы обновляете общедоступное репо, вы обязательно извлекаете только эту ветку и ограничиваете глубину извлечения.

(Вы, вероятно, должны включать один родительский коммит для каждого релиза; по крайней мере, я вспоминаю, что это было необходимо в последней версии, где я тестировал это. В противном случае git не поймет, что «другой» родитель - предыдущий публичный коммит - присутствует, и граф коммитов не выглядит "правильно". Я на 99% уверен, что это всего лишь проблема с инструментом - то есть все данные хранятся правильно - но это все еще делает использование репо труднее, если Вы не включаете один дополнительный коммит глубины.)

repo1 (private)

A -- B -- C -- D -- H -- I -- J
      \         \              \
       E ------- F              \
                  \              \
                   G ------------ K <--(public)


repo2 (public)

        J
         \
F -- G -- K <--(master)

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

0 голосов
/ 22 мая 2019

Мое предложение было бы создать новый репозиторий только с кодом, который вы хотите выпустить в нем. Этот репо будет содержать те же файлы, что и ваш репо, но без какой-либо истории.

Затем, чтобы управлять ими одновременно, вы можете добавить два разных пульта в ваш локальный репозиторий. Это немного странно, потому что большую часть времени, когда вы делаете это, два пульта делят много коммитов, но им это не нужно. В этом случае они будут полностью разделены, расходясь в корне.

Но преимущество добавления обоих этих удаленных репозиториев в ваш локальный репозиторий заключается в том, что вы можете cherry-pick между ними. Когда вы запустите git log, вы увидите историю обоих репозиториев.

Следование этой идее может выглядеть примерно так:

# Move into the old repo on your computer
cd old-repo 

# Rename the default 'origin' remote name to be 'old'
git remote rename origin old 

# Add a new remote repository to your local repository
git remote add new https://github.com/foo/bar 

# See the history of both of these repositories
git log --all --oneline --graph --decorate

И затем, когда вы хотите сделать обновление, начиная со старого репозитория и cherry-pick переходя к новому:

git checkout branch-in-old-repo
git add .
git commit -m "New feature"
git push old branch-in-old-repo

# Now checkout a branch on the latest commit of the new repo
git checkout -b branch-in-new-repo new/master

# Cherry-pick the commit you just made into the new repo
git cherry-pick branch-in-old-repo

# Push that cherry-picked commit to the new repository
git push new branch-in-new-repo

И теперь сделанный вами коммит («Новая функция») существует в обоих репозиториях!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...