Добавить коммиты до фиксации корня в Git?

Новый вопрос

Два вопроса:

  • Я пытаюсь выполнить фиксацию до того, как заработает ВСЕ.
    Самый нижний фиксатор имеет 660fb2a76211f36ec9a67d0454a90eab469e9fd0 как SHA. Когда я набираю git rebase -i 660fb2a76211f36ec9a67d0454a90eab469e9fd0 каждый фиксатор, но последний отображается в списке.
    Мне действительно нужна эта фиксация, чтобы я мог перенести самую последнюю фиксацию как очень последнюю!

  • Когда я помещаю первый коммит как первый в списке (это означает, что второй коммит в целом, потому что самый первый не входит в список, как упоминалось выше), я получаю сообщение об ошибке: error: could not apply b722c76... v1.4.3 BEAT release
    Я просто вырезал его со дна списка и поставил его на первое место! Я не изменил номер!
    Я также пробовал это несколько раз. Тот же результат.

Что это пока. Если у вас есть вопросы, спросите!

Оригинальный вопрос

Я просто изучил старые резервные копии моего проекта. Эти резервные копии создавались до того, как я использовал git.
Теперь я хотел бы добавить их в мой репозиторий, поскольку старые коммиты. Это означало бы, что я должен поставить эти фиксации перед all другими коммитами.

Теперь есть несколько проблем с этим:

  • Как мне вообще поставить фиксацию перед другими?
  • Как я могу сделать это быстро? (У меня много резервных копий!)
  • Как установить дату для этих "старых" коммитов? (Я знаю даты резервных копий!)

Если что-то неясно, укажите это. Тогда я исправлю проблему!

Последнее:

Я опубликовал это на GitHub. И я в основном использовал их программное обеспечение для совершения коммитов. Итак, как я могу вернуть это обратно в GitHub?

Ответ 1

Update

Я нашел другой, немного более простой способ сделать это, используя флаг --root git rebase. Я попробовал это с моим репо, поэтому я знаю, что он работает (по крайней мере, для полностью линейной истории, больше об этом в конце).

Шаг 1: Создайте резервный клон вашего репо

Пусть это безопасно и сделает резервную копию, на случай, если мы закончим что-то катастрофическое и потеряем ваши данные:

git clone original-repo backup-repo

Шаг 2: Создайте сиротскую ветку (это будет ваш новый корень)

Оформить покупку сиротской ветки. Указание фиксации/ветки начальной точки является необязательным, если вы оставите этот аргумент вне, тогда Git по умолчанию будет использовать ваш текущий фиксатор в качестве начальной точки (он следует за шаблоном стандартного синтаксиса ветвления):

git checkout --orphan new-master firstCommitOfOldMaster

Я определил корень старого мастера как начальную точку, потому что он, вероятно, сделает следующий шаг быстрее (удаление файлов рабочего каталога).

Шаг 3: Удалите файлы рабочего каталога

Создание ветки-сироты new-master от вашего старого мастера может оставить файлы в вашем рабочем каталоге и индексе, в зависимости от того, какое состояние файлов было в commit, от которого вы отделились:

Индекс и рабочее дерево настроены так, как если бы вы ранее запускали git checkout <start_point>. Это позволяет вам начать новую историю, которая записывает набор путей, похожих на <start_point>, легко запуская git commit -a, чтобы сделать фиксацию root. — git checkout docs

Теперь вам нужно полностью очистить состояние ветки, так что вы действительно начнете снова с чистого листа (запустите из папки верхнего уровня):

git rm -rf .

Это объяснение из документов:

Если вы хотите запустить отключенную историю, которая записывает набор путей, полностью отличающихся от одного из <start_point>, тогда вы должны очистить индекс и рабочее дерево сразу после создания ветки-сироты, запустив git rm -rf . от верхнего уровня рабочего дерева. После этого вы будете готовы подготовить свои новые файлы, заполнив рабочее дерево, скопировав их из других источников, извлеките архив и т.д.

Шаг 4: Рекомендуем более старую работу в new-master

Теперь вы захотите начать выполнять свою более старую работу в new-master. Когда вы закончите, вы вернете своего старого мастера сверху.

Я не совсем уверен, как организованы ваши резервные папки, но я собираюсь предположить, что каждый из них является только датированной копией папки вашего проекта, названной в формате YYYY-MM-DD, например. 2013-01-30. Вы можете добавить содержимое каждой папки в качестве новой фиксации вручную или написать script для автоматизации процесса.

Предположим, что у вас есть все ваши резервные папки в верхней папке с именем backup, которая находится в том же каталоге, что и ваша основная папка проекта. Затем вот некоторый псевдокод для script для автоматизации процесса компиляции каждой папки:

# Get backups and sort them from oldest to newest
backups = open("backups").toList().sort("date ascending")
for each (backup in backups)
    copy files from backup to project folder
    execute `git add "*"`
    execute `git commit --date="#{backup.date}" --message="#{backup.date}"`

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

Шаг 5: Восстановите старый master на new-master

ПОСМОТРЕТЬ УДИВИТЕЛЬНУЮ ЭНЕРГИЮ, КОТОРУЮ GIT! Теперь мы собираемся ОБНОВИТЬ ВАШУ ИСТОРИЧЕСКУЮ ИСТОРИЮ! Прочитайте эти тайные слова силы и понаблюдайте за волшебством:

git rebase --onto new-master --root master

TA-DA! Возможно, вам придется разрешать конфликты между last-commit из new-master и first-commit из master, но кроме этого, это должно быть!

Флаг --root на rebase обходит проблему, с которой мы столкнулись ранее, о том, что — normal — rebase не будет работать с первым (корневым) фиксацией репозитория Git. Флаг --root в основном сообщает Git включить его в rebase:

Восстановите все коммиты, достижимые с <branch>, вместо того, чтобы ограничивать их <upstream>. Это позволяет вам переустановить корневой фиксатор на ветке. При использовании с --onto он пропустит изменения, уже содержащиеся в <newbase> (вместо <upstream>), тогда как без --onto он будет работать при каждом изменении. — обновить документы

Шаг 6: убедитесь, что конечная фиксация остается тем же самым

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

git diff orig_head   # "Original" head
git diff [email protected]{1}  # Master at its 1st prior position

Если вы не получаете выход из diff, это означает, что конечное состояние вашего rebased master идентично тому, что было до rebase. Хорошая работа!

ПРИМЕЧАНИЕ: не уверен, что происходит для слияния коммитов...

Теперь вышеуказанные шаги будут работать нормально, если у вас есть отличная линейная история, т.е. у вас нет коммитов. Я не уверен, будет ли он работать, если вы это сделаете. В моем предыдущем ответе ниже я упомянул, что использование флага --preserve-merges с rebase может помочь вам сохранить эти слияния, но в документах упоминается, что этот флаг также взаимодействует с флагами --onto и --root:

Когда [--root] используется вместе с --onto и --preserve-merges, все корневые коммиты будут перезаписаны, если вместо этого будет <newbase> как родительский. — обновить документы

Я не совсем уверен, что это значит в данный момент... Мне, возможно, придется попробовать и посмотреть, что произойдет. Означает ли это, что если у вас более 1 корневой фиксации (например, 10), то 9 из этих корневых коммитов в конечном итоге будут переустановлены на последний, действующий как новый корень? Это не похоже на поведение, которое мы хотели бы. Мы просто хотим сохранить фиксацию слияния для того, чтобы один корень был переустановлен на другой.


Предыдущий ответ

У MGA была правильная идея с rebase. Я не уверен, что это исправит вашу проблему, но, возможно, вам нужно сделать новую фиксацию root в своем репо, добавить ваши резервные файлы в качестве новых коммитов поверх нее, а затем перегрузить старый график фиксации сверху.

Например, git checkout имеет флаг --orphan в соответствии с документацией:

--orphan <new_branch>
Создайте новую сиротскую ветвь с именем <new_branch>, начиная с <start_point> и переключитесь на нее. Первая фиксация, сделанная в этой новой ветке, не будет иметь родителей, и она станет корнем новой истории, полностью отключенной от всех других ветвей и совершит.

Итак, вы можете попробовать

git checkout --orphan <temp_branch>

Затем закрепите на нем свои файлы резервных копий. Затем, выведя temp_branch, сделайте

git cherry-pick <first commit from master>
git rebase --onto temp_branch <first commit from master> master

Я думаю, вам, вероятно, понадобится cherry-pick первая фиксация, потому что второй аргумент rebase --onto - это старая база ветки, которую вы хотите переустановить (в данном случае master), а старая база isn ' т включены. Поэтому я считаю, что вам нужно cherry-pick его, чтобы получить его, поскольку он не имеет базового коммита, поэтому вы не можете указать его для него в rebase.

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

-p
--preserve-merges
Вместо того, чтобы игнорировать слияния, попробуйте воссоздать их.

Это использует механизм --interactive внутри, но его сочетание с опцией --interactive явно не является хорошей идеей, если вы не знаете, что делаете (см. ниже).

Итак, возможно, все это сработает?

Ответ 2

1) Вы можете использовать git rebase. В этом случае вы можете сделать следующее:

Прежде всего, перенесите свои старые изменения. Тогда:

$ git rebase --interactive master

Это откроет файл с вашими коммитами в текстовом редакторе. Просто измените порядок коммитов (вырезать/вставить ваши последние коммиты, чтобы быть первыми, включая команду "выбрать" слева), сохранить и закрыть редактор. На этом этапе начнется перезагрузка. Чтобы продолжить, когда вас попросят подтвердить, введите:

$ git rebase --continue

Пока все это не закончится. Дополнительная информация здесь.

2) Я не знаю, какой способ сделать это быстрее, но он должен быть довольно быстрым.

3) Чтобы изменить дату фиксации, вы должны изменить GIT_AUTHOR_DATE и GIT_COMMITTER_DATE. Для этого есть хороший пример fooobar.com/info/5133/....

Надеюсь, что это поможет!