Git pull после принудительного обновления

334

Я просто раздавил некоторые коммиты git rebaseи сделал git push --force(что, я знаю, зло).

Теперь другие разработчики программного обеспечения имеют другую историю, и когда они это сделают git pull, Git объединится. Есть ли способ исправить это, кроме как сделать rm my-repo; git clone git@example.org:my-repo.git?

Мне нужно что-то вроде противоположности git push --force, но git pull --forceне дало ожидаемых результатов.

iblue
источник
16
они могут удалить свою ветку и заново создать ее, не удаляя весь репо:git checkout master && git branch -D test && git checkout -b test origin/test
Флориан Кляйн

Ответы:

512

Чтобы получать новые коммиты

git fetch

Сброс

Вы можете сбросить коммит для локальной ветки, используя git reset.

Чтобы изменить коммит локальной ветки:

git reset origin/master --hard

Будьте осторожны, как сказано в документации:

Сбрасывает индекс и рабочее дерево. Любые изменения отслеживаемых файлов в рабочем дереве после <commit> отбрасываются.

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

Rebase

Вы можете воспроизвести ваши локальные коммиты поверх любого другого коммита / ветки, используя git rebase:

git rebase -i origin/master

Это вызовет rebase в интерактивном режиме, где вы можете выбрать способ применения каждого отдельного коммита, которого нет в истории, над которой вы перебираете.

Если коммиты, которые вы удалили (с помощью git push -f), уже были перетащены в локальную историю, они будут перечислены как коммиты, которые будут применены повторно - их необходимо будет удалить как часть перебазирования, или они просто будут повторно включены в историю для ветки - и вновь появиться в удаленной истории при следующем нажатии.

Используйте справку git command --helpдля получения более подробной информации и примеров по любой из вышеперечисленных (или других) команд.

AD7six
источник
2
@iblue выбирает между потерей всех изменений, удалением истории коммитов, но сохранением изменений файла или попыткой применить каждый коммит поверх новой главы. Самым простым вариантом, вероятно, является мягкий сброс.
AD7six
1
@iblue Когда ваш коллега использует `git reabse origin / master ', а значит, у них уже был какой-то коммит, git запишет ваш коммит за его коммитом.
Тим
6
Стоит упомянуть, что если это для другой ветки:git reset origin/otherbranch --hard
bmaupin
Таким образом, чтобы уточнить, что это либо : Вариант 1: reset --hard, или Вариант 2: reset --soft+ rebase, верно?
PlasmaBinturong
2
@PlasmaBinturong No. git reset --soft origin/masterизменит историю коммитов, чтобы соответствовать удаленным и сценическим различиям, которые затем будут зафиксированы . В этом сценарии не будет необходимости перебазировать (и вам будет запрещено делать это из-за незафиксированных изменений), потому что нет разницы в истории коммитов. Два варианта сбрасываются или перебазируются - не комбинация обоих. Пожалуйста, задайте вопрос, если ваш сценарий отличается от того, на который я ответил здесь.
AD7six
16

Это не исправит ответвления, в которых уже есть код, который вам не нужен (см. Ниже, как это сделать), но если они потянули какую-то ветвь и теперь хотят, чтобы она была чистой (а не «впереди» origin / some-branch) тогда вы просто

git checkout some-branch   # where some-branch can be replaced by any other branch
git branch base-branch -D  # where base-branch is the one with the squashed commits
git checkout -b base-branch origin/base-branch  # recreating branch with correct commits

Примечание. Вы можете объединить их, поставив && между ними.

Примечание 2: Флориан упомянул об этом в комментарии, но кто читает комментарии, когда ищет ответы?

Примечание 3: Если у вас есть зараженные ветви, вы можете создавать новые, основываясь на новой "тупой ветви", и только коммиты "вишня" выбираются.

Пример:

git checkout feature-old  # some branch with the extra commits
git log                   # gives commits (write down the id of the ones you want)
git checkout base-branch  # after you have already cleaned your local copy of it as above
git checkout -b feature-new # make a new branch for your feature
git cherry-pick asdfasd   # where asdfasd is one of the commit ids you want
# repeat previous step for each commit id
git branch feature-old -D # delete the old branch

Теперь новая функция - ваша ветка без лишних (возможно, плохих) коммитов!

Том Пратс
источник
Это то, что я действительно хотел. Кто-то перебазировал основную ветку (для бога знает, по какой причине), но у меня не было локальных изменений, которые я хотел бы зафиксировать или что-то еще. Так что все, что мне нужно было сделать, это удалить мою локальную главную ветку (которая казалась действительно странной) и снова выполнить проверку. Спасибо!
Данило Карвалью,
@ peter-mortensen Изменения должны быть значительными в соответствии со stackoverflow.com/help/editing
Том Пратс
для последнего шага, вы также можете использовать git checkout -b base-branch origin/base-branchсgit checkout --track origin/base-branch
bluesmonk
2

Потяните с ребазой

Обычное извлечение - это выборка + слияние, но вам нужно получить + перебазировать. Это опция с pullкомандой:

git pull --rebase
Герман
источник
Я использую это все время, чтобы получить последний код от мастера в мою ветку функций без всех этих коммитов слияния в истории
Герман