Как раздавить коммиты в git после того, как их толкнули?

551

Это дает хорошее объяснение раздавливания нескольких коммитов:

http://git-scm.com/book/en/Git-Branching-Rebasing

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

РЕДАКТИРОВАТЬ: Когда я это сделаю git rebase -i origin/master~4 master, оставлю первый как pick, установить остальные три как squash, а затем выйти (через cx cc в emacs), я получаю:

$ git rebase -i origin/master~4 master
# Not currently on any branch.
nothing to commit (working directory clean)

Could not apply 2f40e2c... Revert "issue 4427: bpf device permission change option added"
$ git rebase -i origin/master~4 master
Interactive rebase already started

где 2f40 - pickкоммит. И теперь ни один из 4 коммитов не появляется в git log. Я ожидал, что мой редактор будет перезапущен, чтобы я мог ввести сообщение коммита. Что я делаю неправильно?

Loren
источник

Ответы:

781

Сквош совершает локально с

git rebase -i origin/master~4 master

а затем принудительно нажать с

git push origin +master

Разница между --forceи+

Из документации git push:

Обратите внимание, что это --forceотносится ко всем ссылкам, которые передаются, поэтому использование его с push.defaultустановленным значением matchingили с несколькими назначениями push, настроенными с, remote.*.pushможет перезаписывать ссылки, отличные от текущей ветви (включая локальные ссылки, которые строго находятся за их удаленным аналогом). Чтобы форсировать толчок только к одной ветви, используйте + толчок перед опцией refspec (например, git push origin +masterчтобы форсировать толчок к masterветви).

Алан Хаггай Алави
источник
30
Вы также можетеgit push --force origin master
Дейнит
7
Daenyth : Да, но я всегда предпочитаю этот синтаксис, так как он короче.
Алан Хаггай Алави
86
И, конечно, осознайте, что, если кто-то еще мог извлечь из удаленного хранилища, вы, вероятно, не хотите этого делать - ответ в этом случае - «вы этого не делаете».
Каскабель
10
Кроме того, я думаю, что OP точно копирует команду git rebase -i origin/master, и на самом деле хочет знать, как перебазировать коммиты дальше, чем, например git rebase -i origin/master~20 master.
Каскабель
6
gstackoverflow :+форсирует только refspec, которому он предшествует. --forceзаставит все refspecs выдвигаться. Пожалуйста, смотрите обновленный ответ.
Алан Хаггай Алави
120

На ветке я смог сделать это так (за последние 4 коммита)

git checkout my_branch
git reset --soft HEAD~4
git commit
git push --force origin my_branch
Jakob-р
источник
1
Выполнение этого с помощью мягкой команды на уже продвинутой ветке привело к тому, что для меня выдвинулась масса других коммитов.
cchamberlain
3
Тонна? Как это может быть больше 4? Можете ли вы уточнить?
Jakob-R
В этом я не уверен, но это как-то связано с попыткой раздавить уже выдвинутый коммит. Похоже, что другие испытали подобное здесь - stackoverflow.com/questions/5189560/…
cchamberlain
4
Я бы принял это как ожидаемый ответ. Более чистым, что принял ответ.
vikramvi
4
Это самый четкий и принятый ответ всего за 4 шага
Амейя Салагре
45

Незначительная разница с принятым ответом, но у меня было много затруднений при раздавливании, и я наконец получил его.

$ git rebase -i HEAD~4
  • На открывшемся интерактивном экране замените выбор на сквош вверху для всех коммитов, которые вы хотите раздавить.
  • Сохраните и закройте редактор через esc --> :wq

Нажмите на пульт, используя:

$ git push origin branch-name --force
BLRBoy
источник
2
краткий и эффективный, сложный:
terwxqian
22

Множество проблем можно избежать, только создав branchдля работы и не работая master:

git checkout -b mybranch

Следующие работы для remoteкоммитов уже переданы и смесь remoteкоммитов / localтолько коммитов:

# example merging 4 commits

git checkout mybranch
git rebase -i mybranch~4 mybranch

# at the interactive screen
# choose fixup for commit: 2 / 3 / 4

git push -u origin +mybranch

У меня также есть некоторые заметки с запросом на выдачу, которые могут быть полезны

Стюарт Кардалл
источник
17

git rebase -i master

вы получите редактор vm и сообщения что-то вроде этого

Pick 2994283490 commit msg1
f 7994283490 commit msg2
f 4654283490 commit msg3
f 5694283490 commit msg4
#Some message 
#
#some more

Здесь я изменил выбор для всех других коммитов на "f" (обозначает исправление).

git push -f origin feature/feature-branch-name-xyz

это зафиксирует все коммиты в одном коммите и удалит все остальные коммиты. Я сделал это, и это помогло мне.

Nupur
источник
3

Когда вы работаете с Gitlab или Github, у вас могут возникнуть проблемы с этим. Вы раздавливаете свои коммиты одним из вышеуказанных методов. Мой любимый это:

git rebase -i HEAD~4
or
git rebase -i origin/master

выберите сквош или фикс для вашего коммита. На этом этапе вы должны проверить состояние git. И сообщение может быть:

    On branch ABC-1916-remote
    Your branch and 'origin/ABC-1916' have diverged,
    and have 1 and 7 different commits each, respectively.
      (use "git pull" to merge the remote branch into yours)

И вы можете испытать желание потянуть это. НЕ ДЕЛАЙТЕ ЭТОГО, иначе вы окажетесь в той же ситуации, что и раньше.

Вместо этого нажмите на ваше происхождение с:

git push origin +ABC-1916-remote:ABC-1916

Знак + позволяет принудительно толкать только одну ветку.

Alex
источник
в вытягивании нет ничего плохого, особенно если у вас есть конфликты, их можно разрешить легче, чем если бы вы принудительно
нажали
2

Для сжатия двух коммитов, один из которых уже был помещен в одну ветку, работали следующие:

git rebase -i HEAD~2
    [ pick     older-commit  ]
    [ squash   newest-commit ]
git push --force

По умолчанию это будет включать в себя сообщение о коммите самого нового коммита в качестве комментария к старому коммите.

lobsterhands
источник
2

1) git rebase -i HEAD~4

Разработать: Работает на текущей ветке; ГОЛОВА ~ 4 означает сжатие последних четырех коммитов; интерактивный режим (-i)

2) В этот момент редактор открыл со списком коммитов, чтобы изменить второй и последующие коммиты, заменив выбор на сквош, затем сохранив его.

вывод: Успешно перебазирован и обновлен refs /heads / branch-name.

3) git push origin refs/heads/branch-name --force

вывод:

remote:
remote: To create a merge request for branch-name, visit:
remote: http://xxx/sc/server/merge_requests/new?merge_request%5Bsource_branch%5D=sss
remote:To ip:sc/server.git
 + 84b4b60...5045693 branch-name -> branch-name (forced update)
terwxqian
источник