2017-02-22 109 views
3

Я импортирую старый svn repo в git. В какой-то момент папка была переименована во все ветви. Это было сделано в svn, создав дубликат с историей, за которым следует удаление оригинала во второй фиксации. Таким образом, у меня есть репо, который выглядит следующим образом:Как сквош фиксируется в ветвях

A -> B -> C -> D* -> E* -> F -> G -> H 
     \-> 1 -> 2* -> 3* - > 4 -/ 

Где D/E и 2/3 являются коммиты я хочу сквош. Причина того, что svn знает о «дублировании с историей», git не видит это как переименование, так как исходные файлы не удалялись до следующего фиксации, и я теряю историю на вину в этот момент.

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

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

+0

фотография 4, мерзавец перебазироваться -i 1, изменение 2 и 3 фиксаций сквоша, они раздавят вверх в 1 – g19fanatic

+0

Это оставляет меня с осиротевшим 4' , который затем я должен перебазироваться остальной частью моего дерева на. У меня 7-летняя история и почти 100 тыс. Транзакций, а также все ветви и слияния, которые появляются после этого момента, что делает ручную перезагрузку и исправление этой истории очень сложной. – Paco103

ответ

2

Вы хотите использовать git filter-branch с помощью --parent-filter заменить любой вид D 's SHA с C' s SHA. Вы также можете посмотреть .git/info/grafts или git replace, что может быть проще, чем написать --parent-filter и может быть сделанным постоянным с filter-branch.

Обновление: Как сообщает @torek, вы должны обязательно использовать git replace. Чтобы использовать пример в реальной жизни, вот переименование от readme.md до README.md было выполнено с промежуточным переименованием до README1.md: https://github.com/dahlbyk/posh-git/compare/dahlbyk:2b9342c...dahlbyk:57394c5. Давайте назовем 2b9342c ваших C и 57394c5 вашего E:

$ git tag E 57394c5 
$ git tag C 2b9342c 
$ git tag G 450d8f1 
$ git log --oneline --graph --decorate C~..G 
* 450d8f1 (tag: G) Merge pull request #320 ... 
|\ 
| * 941935c Fix a few kbd/missing markdown issues/ 
| * f13dcf9 Upcase readme and have more prompt examples. 
| * 57394c5 (tag: E) Now rename to README.md. 
| * eb79ef2 Prepare to upcase README.md filename. 
* | 536c57f Merge pull request #319 ... 
|\ \ 
| |/ 
|/| 
| * 7fafb7b Speed up Get-GitStatus 
|/ 
* 2b9342c (tag: C) Merge pull request #313 ... 

притвориться, что промежуточный шаг никогда не был, я могу replaceE «родителя (E~) с его прародителем (E~2 = C):

$ git log --stat --oneline C..E 
57394c5 Now rename to README.md. 
README1.md => README.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
eb79ef2 Prepare to upcase README.md filename. 
readme.md => README1.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
$ git replace E~ C 
$ git log --stat --oneline C..E 
57394c5 Now rename to README.md. 
readme.md => README.md | 0 
1 file changed, 0 insertions(+), 0 deletions(-) 
eb79ef2 Merge pull request ... 

И, наконец, a filter-branch будет производить изменения постоянные:

$ git filter-branch -- ^C G E # For demo, only rewrite G & E afer C 
$ git log --graph --oneline --decorate C~..G 
* fcfd345 (tag: G) Merge pull request #320 ... 
|\ 
| * fa76267 Fix a few kbd/missing markdown issues/ 
| * 4900687 Upcase readme and have more prompt examples. 
| * b25aa5a (tag: E) Now rename to README.md. 
* | 536c57f Merge pull request #319 ... 
|\ \ 
| |/ 
|/| 
| * 7fafb7b Speed up Get-GitStatus 
|/ 
* 2b9342c (tag: C) Merge pull request #313 ... 

Для ваших целей, вы будете делать что-то вроде:

$ git replace E~ E~2 
$ git replace 3~ 3~2 
$ git filter-branch -- ^A --all 

Update 2:

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

Чтобы сохранить D «ы фиксации метаданных, Я хотел бы предложить начать сначала и с помощью --commit-filter указать E» ы tree (git cat-file -p E) для D (и что E должны быть пропущены), например,

git filter-branch --commit-filter ' 
    if [ "$GIT_COMMIT" = "SHA of D" ]; 
    then 
    git commit-tree "TREE of E" -p "SHA of C"; 
    elif [ "$GIT_COMMIT" = "SHA of E" ]; 
    then 
    skip_commit "[email protected]"; 
    else 
    git commit-tree "[email protected]"; 
    fi; 
    ' -- ^A E G 
+0

Если вы застряли, оставьте обновление или комментарий с вашим прогрессом, и мы можем попытаться помочь. – dahlbyk

+0

В этом случае я бы рекомендовал дважды запустить 'git replace': во-первых, создать' E'', который указывает на 'C', а Git использует' E'' вместо 'E'; а затем снова сделать '3'', который указывает на' 1', а Git использует '3'' вместо' 3'. Затем, как вы сказали, дополнительно запустите 'git filter-branch', чтобы цементировать замены и полностью отбросить оригинальные' D-E' и '2-3'. – torek

+0

Ах да, не заметил, что для '2-3' нужна была такая же операция. Обновлено. – dahlbyk