Восстановление «старых коммитов» из нескольких мерзавцев git - PullRequest
5 голосов
/ 22 апреля 2010

Мне известен этот вопрос, но я не уверен, как сопоставить его с моей текущей ситуацией. (Перебазировать страшно, отмена - дважды страшно!)

Я начал с нескольких ветвей функций моего мастера:

master    x-x-x-x-x-x-x-x-x-x
             \       \    \
FeatureA      1-2-3   \    \
FeatureB               A-B  \
FeatureC                     X-Y-Z

Я хотел объединить их все вместе и проверить, как они работают, прежде чем вернуться обратно к вершине мастера, поэтому я сделал:

git checkout FeatureB
git rebase FeatureA
git mergetool //etc
git rebase --continue

Тогда

git checkout FeatureC
git rebase FeatureB
git mergetool //hack hack
git rebase --continue

Что оставляет меня с

master    x-x-x-x-x-x-x-x-x-x
             \
FeatureA      1-2-3 
                   \
FeatureB            A'-B'
                         \ 
FeatureC                  X'-Y'-Z'

Затем я исправил некоторые биты, которые не компилировались должным образом, и получил полный набор функций в приемлемом состоянии:

master    x-x-x-x-x-x-x-x-x-x
             \
FeatureA      1-2-3 
                   \
FeatureB            A'-B'
                         \ 
FeatureC                  X'-Y'-Z'-W

Моя проблема в том, что мои коллеги говорят мне, что мы не готовы к FeatureA.

Можно ли как-нибудь сохранить всю мою работу, а также вернуться в ситуацию, когда я могу просто переместить FeatureC в Feature B?

Ответы [ 3 ]

5 голосов
/ 23 апреля 2010

Это мое понимание того, что ответ, на основе комментариев:

Когда вы делаете ребаз, коммиты в вашей текущей ветке «отменяются», затем «применяются», но на самом деле онине отменены, они «запоминаются» * и повторно применяются с новыми идентификаторами, поэтому, например, если я смотрю в git reflog show FeatureB, я получаю что-то вроде этого:

7832f89 FeatureB@{0} rebase finished: refs/heads/FeatureB onto f4df3
efd3fed FeatureB@{1} commit: B
f3f3d43 FeatureB@{2} commit: A
2f32fed FeatureB@{3} branch: Created from HEAD

Итак, как сказал @Jefromi,оригиналы все еще там (SHA коммитов A и B в reflog не совпадают с теми в git log, которые соответствуют A 'и B').

Аналогично, git reflog show FeatureC выглядит такthis

32873ef FeatureC@{0} commit: W
17dafb3 FeatureC@{1} rebase finished: refs/heads/FeatureC onto 89289fe
893eb78 FeatureC@{2} commit: Z
a78b873 FeatureC@{3} commit: Y
e78b873 FeatureC@{4} commit: X
378cbe3 FeatureC@{5} branch: Created from HEAD

Опять же, оригинальные коммиты Z, Y и X все еще там

Итак, решение моей проблемы - создать новую ветку FeaturesBC из HEAD master(например), затем выберите из коммитов FeatureB {2 & 1}, а затем FeatureC {4, 3, 2} и (возможно) W:

git checkout master
git checkout -b FeaturesBC
git cherry-pick f3f3d43 
git cherry-pick efd3fed 
//etc...

(похоже, сработалоМне пришлось повторить некоторые из тех же слияний, но это было не так уж и плохо)

Правка от Джефроми:

Черри-сбор, возможно, не был необходим.Вы также можете просто воссоздать ветки, в которых они находились до перебазирования:

git branch FeatureB-old efd3fed
git branch FeatureC-old 893eb78

Или, если вы хотите отбросить перебазированную позицию FeatureB и FeatureC, вернуться к тому месту, где они были до:

git branch -f FeatureB efd3fed
git branch -f FeatureC 893eb78

Наконец, обратите внимание, что при желании вы можете использовать другие обозначения, представленные в журналах - например, FeatureC@{2} вместо 893eb78.Это означает «вторая предыдущая позиция FeatureC».Будьте осторожны, чтобы использовать это только сразу после просмотра reflog, потому что, как только вы снова обновите ветку (переместите ее, подтвердите ее ...), FeatureC@{2} будет ссылаться на 17dafb3.

Как @Jefromi прокомментировал мой вопрос:

Вы, вероятно, должны были создать новую ветку из master или featureC (скажем, так называемые featuresABC) и слить каждую в нее, оставив ветви функций нетронутыми.Хорошо сохранять независимую историю различных ветвей объектов.

* Если быть точным, старые объекты коммитов просто остаются в хранилище.Они в конечном итоге будут обрезаны, так как вы не хотите репо, полное старых свисающих коммитов;это произойдет при первом запуске git gc, когда коммитам не менее двух недель (настроено gc.pruneExpire).

1 голос
/ 23 апреля 2010

вы можете использовать git rebase --onto <old-merge-base from B> A C, чтобы перебазировать все от C до A на точку на мастере. это оставит вас с:

master    x-x-x-x-x-x-x-x-x-x
             \       \
FeatureA      1-2-3   \
                       \
FeatureB                A'-B'
                            \ 
FeatureC                     X'-Y'-Z'-W

, чтобы найти точку, на которую вы хотите выполнить перебазирование, вы можете использовать комбинацию из git reflog и git merge-base - но вы также можете выполнить перебазирование на базу слияния A, чтобы история была похожа на следующую:

master    x-x-x-x-x-x-x-x-x-x
            |\ 
FeatureA    | 1-2-3
             \
FeatureB       A'-B'
                    \ 
FeatureC             X'-Y'-Z'-W

(git rebase --onto $(git merge-base A master) A C)

1 голос
/ 22 апреля 2010

Если все остальное терпит неудачу, вы можете перезапустить с мастера и git cherry-pick все коммиты B или C воссоздают эти ветви. Я надеюсь, что кто-то другой уже написал сценарий, если это единственное решение ...

...