Подтвердить что ты не робот

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

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

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

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

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

Я действительно хотел, чтобы C * был привязан к происхождению/разработке вместо слияния ветвей.

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

Например, я:

git reset --hard HEAD~1

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

4b9b3361

Ответ 1

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

Скорее всего, вы сделали что-то вроде этого:

<get copy from origin/develop>
<wait around for remote 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 ed этого нового результата, тогда удаленное репо не имеет ни одной из ваших локальных коммитов, те, которые вы отметили C* и M. В этом случае вы в хорошей форме! (Вы можете проверить, запустив git fetch снова, чтобы убедиться, что ваше местное репо origin/develop соответствует тому, которое находится на пульте дистанционного управления, затем выполните git log origin/develop, чтобы узнать, что в нем.)

Это может помочь вспомнить, что здесь есть два совершенно разных git repos: yours, с вашими вещами; и тот, который вы вызываете 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 ed и получили это слияние - тогда вы застряли (в некоторой степени), потому что предположительно другие люди имеют доступ к X и теперь используют вашу транзакцию слиянием. Возможно откат репо на X, подобно тому, как вы можете сделать это в своем собственном репо с git reset и git rebase и т.д., Но, как правило, это плохая идея.


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

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

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

Итак, как вы можете это сделать? Ну, один из способов - войти в X, 2cd в репо (даже если он --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 Этот вид тривиального слияния даже не нуждается в возврате. Там нет ничего принципиально неправильного в том, чтобы покинуть слияние там. Если вы имеете дело с более серьезным ошибочным слиянием, тем не менее, есть еще один недостаток в возврате слияния, помимо записи вашего "oops": он заставляет "переделывать" изменения позже немного сложнее, тем более что "слияние" по назначению "увидит более раннее слияние и подумает: хорошо, мне не нужно повторно объединять эти изменения. Затем вам нужно" вернуть обратно".

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

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

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

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

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