Отменить коммит в удаленной ветке - PullRequest
0 голосов
/ 22 мая 2018

Я работал над локальной веткой, добавляя много коммитов.
Затем я перенес ее в ветку remote staging.

Теперь я должен отменить последний коммит, уже выдвинутый на remote staging, то есть слияние моей локальной ветки с remote staging

Что я понял, глядя на другие ответы, так это то, чтоЯ должен использовать revert, а не reset, чтобы сделать это чистым способом, не так ли?

Итак, что мне нужно сделать, это:

  1. создать новую локальную ветвь с именемнапример, cleaning с master в качестве родителя (который находится за подготовкой)
  2. втягивание пульта staging в очистку
  3. использование git revert {last good commit hash in staging}
  4. сейчас cleaning должен был быть в хорошем коммите и в том же состоянии remote staging до моего плохого пуша, не так ли?
  5. теперь я должен вставить cleaning в remote staging, чтобы удаленная ветвь была возвращена.С какими флагами?

Я прав?Потому что git status в точке 4 говорит мне, что я в курсе staging

Ответы [ 2 ]

0 голосов
/ 23 мая 2018

TL; DR

Помните, что git revert действительно означает отменить изменение , не , чтобы вернуться, т.е. восстановить, какую-то конкретную версию.Можно достичь revert to / restore , но команды, которые это делают, git checkout и git read-tree (обе они слегка хитры по разным причинам).См. Как вернуть Git-репозиторий к предыдущему коммиту? и Откат к старому Git-коммиту в публичном репо (в частности ответ jthill ).

Единственная действительно сложная часть здесь - «отменить слияние».Это равносильно использованию git revert -m 1 в коммите слияния, который достаточно прост для запуска;но это означает, что впоследствии вы не сможете повторно объединить, так как Git совершенно уверен (и правильно), что вы уже объединили всю эту работу и что правильный результат на месте (что это, вы просто отменилиэто позже).Чтобы вернуть все обратно, вы можете отменить возврат.

Возврат создает новый коммит, который, как и каждый коммит, просто добавляет новый коммит в текущую ветку.Вы делаете это в своем собственном хранилище, как всегда.Остальная часть работы заключается в том, чтобы просто отправить новый коммит в какой-нибудь другой Git-репозиторий, добавив его в коллекцию этого другого Git как новый совет одной из их ветвей.

Длинный (подробно)

Во-первых, давайте вернемся немного назад, потому что фраза remote branch ничего не значит, или, скорее, означает слишком много разных вещей для слишком многихразные люди - в любом случае это приводит к сбою связи.

Git имеет ответвлений , но даже слово "ответвление" неоднозначно (см. Что именно мы делаемимеется ввиду под "веткой"? ).Я считаю, что лучше быть конкретным: у нас есть названия филиалов , такие как master и staging и, по вашему предложению, cleaning.Git также имеет имена для удаленного отслеживания или имена для удаленного отслеживания как origin/staging, но, как ни странно, Git сохраняет эти имена локально , т. Е. В вашем собственномхранилище (только).Ваш Git использует your origin/staging, чтобы запомнить, что ваш Git видел на их Git, когда ваш Git последний раз разговаривал со своим Git и спросил их что-то о их staging.

Следовательно, корень проблемы здесь в том, что ваш репозиторий Git ваш , но есть второй репозиторий Git, который не ваш,и в конечном итоге вы хотели бы сделать что-нибудь в этом другом хранилище Git.Ограничение здесь состоит в том, что ваш Git позволяет вам делать это только в вашем хранилище, после чего вы в конечном итоге запустите git push.Шаг git push переведет некоторые коммиты или коммиты из вашего Git-репозитория в их Git-репозиторий.В настоящее время вы можете попросить их Git установить их имя - их staging - и они либо скажут Да, я установилчто (ваш Git теперь обновит ваш origin/staging, чтобы запомнить это), или Нет, я отказываюсь устанавливать это по следующей причине: _____ (укажите причину здесь) .

Следовательно, то, что вы собираетесь делать в вашем репозитории, настроено на соответствующие шаги так, чтобы их Git, в их репозитории, принял коммитвы git push и обновите их staging.Имейте это в виду, когда мы пройдем эти шаги.Есть несколько способов сделать это, но вот те, которые я бы использовал.

  1. Выполнить git fetch.Эта команда всегда безопасна для выполнения.Вы можете дать ему имя одного конкретного пульта, если у вас их больше одного, но у большинства людей есть только один с именем origin, и если у вас есть только один, его не нужно называть.

    (Название пульта - origin - в основном является кратким способом написания URL-адреса, который ваш компьютер должен использовать для доступа к другому хранилищу Git.)

    Thisgit fetch может ничего не делать или может обновлять некоторые ваши имена для удаленного отслеживания (origin/*).git fetch вызвал другой Git, получил от него список всех его веток и хеш-коммитов, которые идут вместе с ними, а затем перенес их на любой коммит, который у вас нет.Ваш origin/staging теперь помнит их staging.Теперь вы можете добавить новый коммит к этому.

  2. Теперь, когда ваш origin/staging синхронизирован с другим Git staging, создайте или обновите имя локальной ветви какнеобходимо.Лучшее имя для использования здесь - staging, но вы можете использовать cleaning, если хотите.Поскольку этот шаг создать или обновить , он имеет подэтапы:

    • Если это «создать», вы можете использовать git checkout -b staging origin/staging для создания нового staging у которого вверх по течению origin/staging.

      Вы можете сократить его до git checkout staging, который - поскольку у вас нет своего staging - будет искать по всем вашим origin/* именам (и любымдругие имена удаленного отслеживания, если у вас есть более одного удаленного), чтобы найти, какие из них соответствуют.Затем он действует так, как будто вы использовали более длинную команду.(Имея только один пульт, единственное имя, которое может соответствовать, это origin/staging. Если у вас есть и origin, и xyzzy в качестве пультов, вы можете использовать и origin/staging, и xyzzy/staging; тогда вам понадобится большекоманда.)

    • Или, если это «обновление», у вас уже будет staging, для которого уже установлено origin/staging в качестве восходящего потока, потому что вы делали это раньше.В этом случае просто запустите:

      git checkout staging
      git merge --ff-only origin/staging
      

      , чтобы синхронизировать вашу постановку с origin/staging.Если слияние ускоренной перемотки завершится неудачно, у вас есть некоторые коммиты, которых нет, и вам понадобится что-то более сложное, но мы будем предполагать, что это успешно.

      Вы можете сократить эти командынемного, но я оставлю их изложенными здесь.Обратите внимание, что первая команда - это такая же , как у короткой версии для первого случая выше, и вы можете определить, какая из них произошла по выводу git checkout staging.(Я оставлю детали для других вопросов или упражнений.)

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

    ...--o--o--o---M   <-- staging (HEAD), origin/staging
             \    /
              o--o   <-- feature/whatever
    

    Каждый раунд o представляет коммит.M представляет коммит слияния, результат которого вам не нравится, но который также присутствует в другом Git на origin в их имени staging, поэтому ваш собственный Git имеетимя origin/staging, указывающее на фиксацию M.

  3. Теперь вы хотите создать фиксацию, которая отменяет неверную фиксацию.Скорее всего, здесь будет использоваться git revert, но помните, что возврат означает отменить или возврат , а не переключение на старую версию .Вы сообщаете Git, какой коммит отменить, а Git отменяет его, выясняя, что вы сделали, и поступая противоположным образом.

    Например, если коммит, который вы говорите для возврата, говорит «удалить файл README», изменениебудет включать «восстановить файл README в том виде, в каком он был при удалении».Если в коммите, который вы говорите для возврата, написано «добавить эту строку в Documentation / doc.txt», изменение будет включать «удалить эту строку из Documentation / doc.txt».Если в коммите, который вы говорите «отменить», написано «изменить привет на прощание» в каком-то третьем файле, изменение, которое произойдет для возврата, - это изменить «до свидания» на «привет» в этом третьем файле, в той же строке (с некоторой магиейстрока, если она была перемещена).

    Это означает, что git revert может отменить любой коммит, даже если это не последний коммит.Однако для этого он должен сравнить этот коммит со своим непосредственным родителем .Если коммит, который вы пытаетесь вернуть, является коммитом merge , он имеет более одного родителя , и вам нужно будет указать, какой родительский Git следует использовать.

    правильный родитель для использования не всегда сразу очевиден.Однако для большинства слияний это просто «родительский номер 1».Это потому, что Git делает особый акцент на первом родителе слияния: это коммит, который был HEAD, когда вы запустили git merge.Так что это все, что принесло слияние, чего еще не было.

    Когда git revert завершается успешно, он делает новый коммит, который отменяет эффект слияния:

                     W   <-- staging (HEAD)
                    /
    ...--o--o--o---M   <-- origin/staging
             \    /
              o--o   <-- feature/whatever
    

    Здесь W представляет этот новый коммит: он M перевернут вверх дном.Все, что вам нужно сделать сейчас, это запустить git push origin staging, чтобы отправить свой новый коммит W другому Git:

  4. git push origin staging: это вызывает этот другой Git и предлагает егоcommit W - это каждый наш коммит, которого нет;у них есть M и все ранее (слева), но не W.

    Пока нет особых ограничений, они примут этот новый коммит и изменят свои staging для указания нового коммита W.Ваш Git запомнит это изменение:

                     W   <-- staging (HEAD), origin/staging
                    /
    ...--o--o--o---M
             \    /
              o--o   <-- feature/whatever
    

    (Нет необходимости продолжать рисовать W на отдельной строке, но я использую здесь копирование-вставку, чтобы сохранить форму такой же.)

Как видите, все готово.Вы и они оба согласны, что вы и их staging должны оба указать на фиксацию W, которая приводит к отмене фиксации M.Теперь можно безопасно удалить собственное имя staging, если вам нравится:

git checkout <something-else>
git branch -d staging

, что приводит к:

...--o--o--o---M--W   <-- origin/staging
         \    /
          o--o   <-- feature/whatever
0 голосов
/ 22 мая 2018

Не усложняйте.

Сначала вам нужно сделать git log, чтобы узнать, какой идентификатор фиксации вы хотите вернуть.Например, это commit abc123.Если вы знаете, что это последний, вы можете использовать специальный идентификатор «HEAD».

Затем вы сначала возвращаете его локально в локальной «промежуточной» ветке:

git checkout staging
git revert abc123

Примечание:для последнего коммита в журнале вы должны написать git revert HEAD.

И затем вы обновите свою «промежуточную» удаленную систему:

git push

Объяснение: В git, если у вас есть пульт, выработа с 2 различными хранилищами (локальным и удаленным)После того, как вы выполните git checkout staging, вы фактически создадите отдельное локальное имя, представляющее удаленную ветвь.git revert фактически не удаляет ваш коммит, но он создает новый коммит поверх, который отменяет все изменения (если вы добавили файл - новый коммит удалит его, если вы удалили строку - новый коммит добавитобратно и т. д.), то есть это дополнение к журналу, поэтому толчок будет чистым.

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

git checkout staging
git reset --hard HEAD^
git push -f

(строка сброса перенаправляет локальную «промежуточную» ветвь так, чтобы она указывала на коммит, который находится прямо перед вашим верхним коммитом)

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

git checkout staging
git checkout -b staging2
git reset --hard HEAD^
git push
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...