Отменить слияние, которое было перенесено

Хорошо, я сделал немного беспорядка. Судя по всему, на моей машине дома развивающая ветка не обновлялась. Я сделал коммит и толкнул. Результатом было то, что фактическая ветвь происхождения / разработки была объединена с моей локальной ветвью разработки - которые по некоторым причинам рассматривались как разные ветви!

Во-первых, я действительно не понимаю, как это произошло, и, во-вторых, могу ли я отменить это?

Чтобы проиллюстрировать это, сеть теперь выглядит примерно так:

 local-develop ---------------------------------- C*--- M -
origin/develop --- C --- C --- C --- C --- C --------- / 

Что я действительно хотел, так это то, что C* будет стремиться к возникновению / разработке вместо слияния ветвей.

Как я уже сказал, это уже подтолкнуло. Есть ли способ удалить изменения и зафиксировать их так, как я хотел?

Например я делаю:

git reset --hard HEAD~1

Я не уверен, что это отменяет слияние, и у меня есть две разные разработки, а затем слияние удалено и т.д...?

2 ответа

Решение

Слияния не происходят на толчке, они случаются на git merge (хорошо и pull но это действительно просто выборка + слияние, следовательно, слияние происходит при слиянии).

Кажется более вероятным, что вы сделали что-то вроде этого:

<get copy from origin/develop>
<wait around for remote's origin/develop to acquire new commits>
git checkout develop      # get onto (local) develop branch
<edit>
git commit -m message     # create some new commit(s)
git push origin develop   # attempt to push -- but this fails!
git pull

Это последний шаг, который создает коммит слияния (M выше), потому что pull средства fetch (получить все те новые коммиты, которые сейчас находятся в origin/develop), затем merge (возьми свой местный develop и объединить ваш коммит с только что полученными новыми).

Если у вас нет git push После этого нового результата в удаленном репо не будет ни одного из ваших локальных коммитов, помеченных вами C* а также M, В этом случае вы в хорошей форме! (Вы можете проверить, запустив git fetch еще раз, чтобы убедиться, что ваш местный репо origin/develop соответствует тому, что в пульте, затем делает git log origin/develop чтобы увидеть, что в этом есть.)

Это может помочь вспомнить, что здесь есть два совершенно разных git-репозитория: ваш с вашими материалами; и тот, кого вы называете origin Вот. (Давайте назовем эту машину X.) Если бы вы должны были войти в X, у него есть своя отдельная история коммитов и имена веток и так далее. Там вы бы сменили каталог на репо, запустили git log -1 develop и посмотрим, что на кончике этой ветви.

Теперь, если вы выйдете из X и вернулись на свою машину, вы можете запустить git log -1 origin/develop, Если это то же самое, что вы видели на X, затем get fetch обновлять нечего, потому что git fetch в действительности (но более эффективно) войти в X и посмотрите, что в develop там. Все, что X имеет то, что у вас нет в origin/develop, fetch приносит и добавляет к origin/develop, Теперь вы синхронизированы с X, X нет ваших вещей, но у вас есть их.

Если вы затем сделаете дополнительный шаг merge (включая тот, который подразумевается pull git, если нужно, сделает коммит слияния... но все это в вашем репо на кончике ветки (все еще develop в этом случае). Если и до тех пор, пока вы не нажмете это слияние совершить X (или кто-то на X тянет ваши коммиты от вас, но давайте пока проигнорируем это:-)), X не будет этого

Во всяком случае, пока удаленный (X здесь) не твой коммит слияния, ты золотой. Так как у них его нет, больше никто не делает. Вы можете сделать rebase вашей develop ветка поставить свой коммит (C*) на вершине origin/develop, Это избавит от коммита слияния (M), а затем вы можете нажать простой перемотки вперед origin/develop,

Если X есть ли у вас коммит слияния - то есть, если вы нажали после pullи получили это слияние - тогда вы застряли (до некоторой степени), потому что, вероятно, другие люди имеют доступ к X и теперь используете ваш коммит слияния. Можно откатить репо на X аналогично тому, как вы можете сделать это в своем собственном репо с git reset а также git rebase и так далее, но это вообще плохая идея.


Теперь предположим, что вы действительно подтолкнули к другому репо (на машине X), но вы абсолютно уверены, что никто еще не видел ваши изменения, и вы определенно собираетесь сбросить их, а не возвращать их (возвращая суммы к "признанию" и оставляя запись обмана позади, что позволяет всем остальным выздороветь от этого легко, но также позволяет им увидеть вашу ошибку:-)). 1

Вот хитрость: сначала вы должны получить репозиторий машины X, чтобы сказать, что "верхушка ветки" devel это коммит C7", где C7 находится в вашей собственной диаграмме из предыдущего, просто перенумеровал, чтобы я мог называть каждый коммит по-разному:

--------------------------- C*--- M
--- C4 --- C5 --- C6 --- C7 ---- /

Итак, как вы можете это сделать? Ну, один из способов это войти в систему X, 2 cd в репо (даже если это --bare) и использовать git update-ref там. Скажем, SHA1 для C7 на самом деле 50db850 (как показано в "git log"). Тогда вы можете сделать это:

localhost$ ssh X
X$ cd /path/to/repo.git
X$ git update-ref refs/heads/develop 50db850

Но если вы не можете войти в X или даже просто не хотите, вы можете сделать то же самое с git push -f, 3 (Это имеет и другие преимущества: в частности, ваш git-репо будет знать, что origin/develop был перемотан, как только push -f завершается успешно.) Просто создайте локальную ветку, указывающую на правильный коммит: 4

localhost$ git branch resetter 50db850
localhost$ git log resetter         # make sure it looks right
...
localhost$ git push -f origin resetter:develop
Total 0 (delta 0), reused 0 (delta 0)
To ssh://[redacted]
 + 21011c9...50db850 resetter -> develop (forced update)
localhost$ git branch -d resetter   # we don't need it anymore

Как только вы это сделаете, машина X вернется в нужное вам состояние, и вы сможете продолжить, как если бы вы никогда не нажимали на слияние, которое вам не нравилось.

Обратите внимание, что когда вы делаете push -f Если кто-то еще сделал новые коммиты поверх M они также станут невидимыми (технически они все еще там, вместе с вашим коммитом слияния, но они "потеряны" в lost+found Чувство git fsck --lost-found и через несколько месяцев они действительно уйдут навсегда). 5

Снова и очень важно: этот вид "отката общего репо" является большой болью для других пользователей этого общего репо, поэтому убедитесь, что все в порядке, прежде чем сделать это.


1 Этот тип тривиального слияния даже не нуждается в возврате. Нет ничего принципиально неправильного в том, чтобы оставить слияние там. Если вы имеете дело с более серьезным ошибочным слиянием, есть еще один недостаток, связанный с возвратом слияния, помимо записи ваших "упс": это затрудняет "повторное" внесение изменений позже, в том смысле, что последующее "слияние" нарочно "увидит более раннее слияние и подумает: хорошо, мне не нужно повторно объединять эти изменения. Затем вы должны "отменить возврат" вместо этого.

Я думаю, что правильный урок на вынос здесь: look ( git log ), прежде чем нажать, чтобы убедиться, что то, что вы собираетесь нажать, - это то, что вы намерены нажать.

2 Или все проще и проще: git ls-remote, Это использует код протокола выборки, чтобы увидеть, что есть у пульта. Но здесь скрывается тема, которую я здесь обсуждаю: удаленный репозиторий, как и ваша!

3 В будущих выпусках git версии 2 появятся новые "функции безопасности", которые можно будет использовать с git push -f, Но они еще не вышли, так что это не поможет вам. Я отредактирую это позже, когда они будут, чтобы отметить их. А пока, будьте очень осторожны: вы соревнуетесь с кем-то еще, пытаясь добавить новые вещи в общий репозиторий, на данный момент.

4 Вы даже можете сделать это с помощью необработанного идентификатора SHA-1. Хотя название ветки проще набрать правильно несколько раз подряд.

5 Сохранение и истечение срока действия через git "reflogs". Общий сервер может не регистрировать все обновления обновлений; если нет, то только частные репозитории, которые уже имеют новые коммиты, сохранят их. Самый короткий срок действия по умолчанию составляет 30 дней, т. Е. Около одного месяца, для коммитов, более недоступных из подсказки ветви. Но обратите внимание, что это неинтересная, сумасшедшая схватка, которая заставляет всех искать в своих репозиториях "потерянные" коммиты после принудительных толчков "потерять работу" из общего репозитория.

Здесь ответы Линуса Торвалса Здесь ответы Линуса Торвалса http://opensource.apple.com/source/Git/Git-26/src/git-htmldocs/howto/revert-a-faulty-merge.txt

Другие вопросы по тегам