2014-08-29 2 views
2

У меня есть репозиторий с рядом коммитов. Допустим, два старых коммиты являются А и непосредственно после того, как C:Git: Как я могу поместить фиксацию между более старыми коммитами без изменения файлов/папок последующих коммитов?

A--C 

В фиксации CI имеют не проверяется в новой версии старых файлов, но на самом деле совершенно новые файлы с тем же имя.

Это делает diff для commit C выглядеть беспорядочным - на самом деле этот diff не имеет смысла, так как файлы полностью разные.

То, что я хочу, чтобы добавить фиксации между А и С (давайте назовем это один B тогда):

A--B--C 

В этой фиксации BI необходимо удалить файлы и папки, которые я изменил с C .

Я знаю, что с нижеследующим я могу добавить новое обязательство между A и C:

git rebase --interactive A^ 

затем делает «изменить» на совершающие

, а затем

git rm -rf file folder/ 
git commit -m "B" # New commit with name B 

Как теперь получить те же файлы и папки, которые я имел после первоначальной фиксации C, а это означает до того B был на месте?

Другими словами: Как я могу получить C снова, но без удаление, которое я сделал в B?

+0

Как насчет, обновите до A, совершите B, перебазируйте C сверху B? Или как насчет того, чтобы просто совершить B поверх A, сливаясь с C, а затем добавить новый набор изменений поверх слияния, чтобы удалить ненужные части? Вы действительно хотите изменить историю? –

+0

После того, как я совершил B поверх A, я попробовал 'git rebase --onto HEAD A master'. Это приведет к перестановке C сверху B, однако это (логически) дает серию конфликтов слияния. Это та ситуация, которую я хотел избежать ... – Christopher

ответ

0

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

git checkout A 
git rm -rf file folder/ 
# Create a new commit with name B on top of A: 
git commit -m "B" 
# On top of B create a new commit with what was C: 
echo 'new C commit' | git commit-tree C^{tree} -p HEAD 

Это создаст новый C совершающие и возврат его SHA-хэш.На этом этапе проверка нового C commit содержит именно то, что вы получили бы, если вы проверили оригинал C commit.

git checkout new-C-commit # No, this did not happen with git commit-tree 
git rebase --onto HEAD C master 

Это rebases ветвь (в моем случае это мастер), начиная с первой фиксации после оригинала C фиксации на новом C фиксации. Это будет применяться без проблем, так как оба автоматически создают одинаковые файлы и папки.

+0

Благодаря knittl для установки меня на правильном пути! Кудос идет к нему! – Christopher

1

Вы можете использовать git-commit-tree для этого:

git checkout A 
git rm -rf file folder/ 
git commit -m 'B' 
echo 'new C commit' | git commit-tree C -p HEAD 
# create a new branch/update branch with the commit id printed by commit-tree 

Это:

  • Checkout A (отрывать ГОЛОВА)
  • Удалить файлы и папки, создавать новые фиксации B
  • Создать новый фиксация с тем же набором файлов/состояние, что и исходное сообщение. C
  • Затем вы должны обновить свою старую ветку, чтобы указать на новую фиксации (в настоящее время все еще отдельностоящая ГОЛОВА)

Альтернативный способ может быть использование трансплантатов, а затем фильтр-ветви, чтобы сделать их постоянными:

git checkout A 
git rm -rf file folder/ 
git commit -m B 
echo `git rev-parse C` `git rev-parse HEAD` >> .git/info/grafts 
git filter-branch A^..C 
+0

Я пробовал первый способ, который вы предложили. Однако 'git commit-tree C -p HEAD' не работает. Он дает: * fatal: C не является допустимым «древовидным» объектом * (Фактически я заменил «C» в вашей команде на commit-SHA соответствующего коммита, и этот SHA также является тем, что упоминается в выводе ошибки). – Christopher

+0

@Christopher: попробуйте 'C^{tree}' (замените C своим именем хеша/ветки вашего коммита) – knittl

+0

Похоже, что это приводит меня к решению. Я дважды проверю, а затем отправлю шаги, которые я должен был сделать ... – Christopher