Как задним числом добавить коммиты в репозиторий Git?

Я создаю модуль, который переносит стороннюю библиотеку на другую платформу. Версия моего модуля соответствует версии библиотеки, которую он обертывает.

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

Git-ссылки выглядят так:

master === HEAD === v10 (tag)

Однако из соображений совместимости я также хочу создать версии 8 и 9 оболочки.

Если я зафиксирую v9, он станет новым HEAD, но я хочу, чтобы HEAD остался на v10. Я просто хочу, чтобы v9 был доступен через

// switch to version 9
git checkout v9

Есть какой-либо способ сделать это?

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


person Mulan    schedule 11.08.2013    source источник
comment
Для перебазирования см. также Git для начинающих: полное практическое руководство< /а>. Я также настоятельно рекомендую БЕСПЛАТНУЮ онлайн-книгу Pro Git, в частности главы 1-3, 6-6.5. Вы также можете посмотреть мой профиль на других ресурсах Git.   -  person    schedule 12.08.2013
comment
См. также git rebase vs git merge.   -  person    schedule 12.08.2013
comment
Забавно, всякий раз, когда я ищу определенные типы вопросов о ретроактивном добавлении коммитов в репозиторий Git, этот вопрос продолжает появляться.   -  person    schedule 22.07.2014


Ответы (1)


Вопрос немного необычный / неясный, в основном потому, что он, похоже, не задан в «Пути Git» / контексте просмотра системы управления версиями. «Головы» в Git имеют более одного значения... это не означает то же самое, что и в SVN, например. К этому моменту я вернусь позже, но сейчас я попытаюсь решить то, что кажется проблемой добавления предыдущих версий базы кода в репозиторий Git.

Как задним числом добавлять коммиты в Git

У вас есть как минимум два варианта:

  1. Добавьте предыдущие версии кодовой базы как потерянные, отдельные ветки. Это не то, что я рекомендую, потому что, по моему опыту, потерянные ветки неэффективны для переключения между ними в вашей рабочей копии, вероятно, потому, что операция checkout не имеет доступа к общим предкам и тому подобному.
  2. Вы можете добавить предыдущие версии как осиротевшие ветки, но затем перебазировать новейшую ветку v10/master поверх них и добавить новые теги.

Я рекомендую вам использовать вариант № 2, так как это проблема, которая ранее решалась в Stack Overflow, и для решения этой проблемы больше подходит «Путь Git»:

  1. git: как вставить коммит первым, смещая все остальные?
  2. Git: как добавить коммиты перед first/initial/root совершить?)

В частности, я рекомендую вам выполнить следующие основные шаги, которые я даю подробное объяснение в этом ответе:

  1. Создайте резервную копию вашего репозитория:

    git clone original-repo backup-repo
    
  2. Создайте ветку-сироту (это будет ваш новый корень).

    git checkout --orphan new-master firstCommitOfOldMaster
    
  3. Удалить файлы рабочего каталога из ветки-сироты.

    git rm -rf .
    
  4. Повторно передать старую работу в new-master.

  5. Перебазируйте старый master на new-master.

    git rebase --onto new-master --root master
    
  6. Убедитесь, что окончательный коммит не изменился.

    git diff master@{1}
    

Либо до того, как вы перебазируете старый мастер на новый, либо после этого вы можете пометить свою ветку v9 тегом облегченный тег или аннотированный тег:

# Lightweight
$ git tag "v9"

# Annotated
$ git tag -a "v9" -m "Tag version 9"

Объяснение ГОЛОВЫ

Таким образом, «головы» в Git имеют несколько значений, в зависимости от контекста. В контексте, который вы используете в качестве фиксации, ссылкаHEAD просто означает фиксацию, которую вы в настоящее время извлекли в свою рабочую копию. Это не означает то же самое, что и в SVN, то есть HEAD не представляет самую последнюю глобальную фиксацию в репозитории.

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

  1. Что такое git HEAD?.
  2. HEAD и ORIG_HEAD в Git.

В Git есть еще один контекст, где используются «заголовки»: ветки, которые являются локальными по отношению к репозиторию, обычно хранятся в каталоге .git/refs/heads/. В этом контексте «головы» означают просто указатели/ссылки на ветки и являются «советами»/самой последней фиксацией для ветки. Вы можете увидеть заголовки/подсказки ветки вашего локального репо, запустив git show-ref:

git show-ref
35ec88f1c5b319b7ca08f5d3dca3cafdebddecd4 refs/heads/awesome-feature
ea112e91953e02f9c6dcc7b9470b8bdf0a69a3eb refs/heads/epic-feature
a9874fd23f67c245fadd23bef449971fa7338755 refs/heads/master

Здесь вы можете видеть, что у меня есть 3 главы/подсказки/ссылки веток: ветка master, ветка awesome-feature и ветка epic-feature. Слева от каждой ветки вы увидите полный коммит sha, на который в данный момент указывает ветка, то есть самый последний коммит для этой ветки.

Объяснение перебазирования

Прежде всего, позвольте мне начать с того, что вы должны научиться rebase. Период. Я утверждаю, что это самый фундаментальный, важный и мощный инструмент Git, и если вы его не используете, значит, вы используете Git неэффективно. Так что научитесь перебазировать как в интерактивном, так и в неинтерактивном режиме.

С учетом этого я не буду вдаваться в подробности о том, как работает git rebase, так как есть много онлайн-ресурсов, объясняющих это (я перечислю их), и этот ответ уже очень длинный.

Но в двух словах, rebase позволяет вам переписать вашу историю практически любым способом, которым вы можете захотеть. Он берет набор коммитов и повторно применяет копии этих коммитов к любому месту в вашей истории. Вот что делает решение, которое я предложил выше: оно берет вашу старую историю v10 и воссоздает ее поверх новой истории v9, как будто история всегда создавалась таким образом.

Перебазировать ресурсы

Вот отличные ресурсы для получения дополнительной информации о rebase. Помните, что вы всегда можете создать тестовый репозиторий Git, полный .txt файлов или чего угодно, а затем попрактиковаться в ветвлении, перемещении и слиянии с ним:

  1. Инструменты Git — история перезаписи.
  2. страница руководства git-rebase(1) .
  3. Изучите ветвление Git, см. демонстрацию Interactive Rebase.
  4. Курс Code School Git Real, урок 6.
person Community    schedule 11.08.2013
comment
+1. Это имеет большой смысл. У меня все еще есть один оставшийся вопрос. Скажем, у меня зафиксированы v1 и v3, но я хочу добавить v2. Могу ли я branch отказаться от v1, commit v2, затем rebase v3 на v2? Должен ли я сделать что-нибудь, чтобы исправить v4+ на данный момент? - person Mulan; 12.08.2013
comment
Кроме того, если есть версии, уже отправленные в общедоступный репозиторий, не следует ли мне rebase существующие ветки? Как мне обойти это ограничение? - person Mulan; 12.08.2013
comment
@naomik относительно перебазирования коммитов в общедоступном репо, как правило, это не рекомендуется, потому что это заставляет людей повторно синхронизировать любые коммиты, которые они сделали на основе старой истории, с новой историей, что иногда может быть сложно. Однако если вы можете быть уверены, что никто другой на самом деле не основывал какие-либо коммиты/работы на вашей старой истории, или вас не волнует, что другие люди вынуждены выполнить повторную синхронизацию, то нет технических ограничений, которые помешали бы вам изменить базу общедоступной истории. - person ; 12.08.2013
comment
@naomik, если, с другой стороны, вас не волнует, что другие люди вынуждены повторно синхронизировать работу, то перебазирование не подходит. Навскидку, я не знаю никаких обходных решений, но если я что-то придумаю, я добавлю это в качестве ответа. - person ; 12.08.2013
comment
@naomik относительно вашего первого комментария, мне нужно больше контекста, потому что странно, что ваши теги версии еще не настроены так, что вам вообще не нужно ничего перебазировать. Как вы управляете версиями/тегами и ветвями в своем репо? Если это общедоступно, могу ли я получить URL-адрес для его просмотра? - person ; 12.08.2013
comment
исходные версии не были частью репозитория моего модуля. Я просто хотел начать с текущей версии и предоставить более старые версии для людей, которым нужна конкретная (более старая) версия. - person Mulan; 12.08.2013
comment
Кроме того, библиотека, которая запакована в мой модуль, имеет много версий. Я не хотел делать всю эту работу в одиночку. Я более-менее хотел привести пару примеров, а затем дать людям руководство по легкому форку/вытягиванию запроса в конкретной версии, если она еще не поддерживается. - person Mulan; 12.08.2013
comment
давайте продолжим это обсуждение в чате - person Mulan; 12.08.2013
comment
Обратите внимание: мне нужно обновить информацию в моем ответе, чтобы объяснить HEAD как символическую ссылку. - person ; 22.07.2014