Как мне использовать 'git rebase -i', чтобы отменить все изменения в ветке?
Вот пример:
>git status
# On branch master
nothing to commit (working directory clean)
>git checkout -b test-branch
>vi test.c
>git add test.c
>git commit -m "modified test.c"
>vi README
>git add README
>git commit -m "modified README"
Теперь я хочу сделатьgit rebase -i
"Это позволит мне перебазировать все коммиты для этой ветки. Есть что-то вродеgit rebase -i HEAD~MASTER
' или похожие. Я полагаю, я мог бы сделатьgit rebase -i HEAD~2
', но я действительно не хочу считать, сколько было сделано коммитов. Я мог бы также сделатьgit rebase -i sha1
'но я не хочу прочесывать журнал git, чтобы найти первый коммит sha1. Есть идеи?
8 ответов
Хорошо, я предполагаю, что ветка называется "особенность", и она была разветвлена от "мастера".
Эта маленькая команда git называется merge-base. Он берет два коммита и дает вам первого общего предка обоих. Так...
git merge-base feature master
... даст вам первого общего предка этих двух коммитов. Угадайте, что происходит, когда вы передаете этот коммит git rebase -i, например...
git rebase -i `git merge-base feature master`
Интерактивный ребаз от первого общего предка как основной, так и функциональной ветви. Прибыль!;)
Проблема со всеми предоставленными решениями заключается в том, что они не позволяют вам выполнить ребазинг с самого первого коммита. Если первый коммит хеша XYZ и вы делаете:
git rebase -i XYZ
Вы делаете ребаз только начиная со 2-го коммита.
Если вы хотите сделать ребаз с первого коммита, который вы делаете:
git rebase -i --root
Используйте gitk (*nix), или gitx (OS X) или аналогичные на других платформах, и посмотрите, какой коммит был корнем вашей ветви. Затем запустите:
git rebase -i <the SHA hash of the root commit>
Например, у меня есть репозиторий, который я проверил с помощью gitx:
Теперь, когда я знаю корневой хэш, я могу запустить это:
git rebase -i 38965ed29d89a4136e47b688ca10b522b6bc335f
И мой редактор всплывает с этим, и я могу изменить / сквош / все, что угодно.
pick 50b2cff File 1 changes.
pick 345df08 File 2 changes.
pick 9894931 File 3 changes.
pick 9a62b92 File 4 changes.
pick 640b1f8 File 5 changes.
pick 1c437f7 File 6 changes.
pick b014597 File 7 changes.
pick b1f52bc File 8 changes.
pick 40ae0fc File 9 changes.
# Rebase 38965ed..40ae0fc onto 38965ed
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
Я уверен, что есть какой-то волшебный способ убедить git автоматически определить корень дерева, но я не знаю, что это такое.
РЕДАКТИРОВАТЬ: Это волшебство это:
git log master..other_feature | cat
Который покажет вам все коммиты в этой ветке, а пайп к кошке отключит пейджер, так что вы сразу увидите первый коммит.
РЕДАКТИРОВАТЬ: сочетание вышеупомянутого дает полностью автоматизированное решение:
git rebase -i `git log master..other_feature --pretty=format:"%h" | tail -n 1`~
Проблема с ребазингом из другой ветки
Проблема с git rebase -i master
в том, что у вас могут возникнуть конфликты слияния, с которыми вы не обязательно хотите иметь дело в данный момент, или вы можете исправить конфликт в одном коммите, только чтобы исправить его снова в другом коммите в ходе перебазирования.
Проблема с перебазированием из известного коммита
Вся проблема здесь в том, что вы должны знать, на какой коммит вы ссылаетесь, либо по его SHA, либо по HEAD~x и т. Д. Это только незначительное раздражение, но это раздражение.
Лучший способ
Если вы вместо этого хотите перебазировать все коммиты в вашей текущей ветке, так как последний коммит делился с его родительской веткой, вы можете добавить следующий псевдоним в.gitconfig:
rbi = !sh -c \"git rebase -i `git merge-base $1 HEAD`\" -
использование
git rbi parentBranch
Как это устроено
Этот псевдоним является просто сценарием оболочки, который использует аргумент, который ссылается на родительскую ветвь. Этот аргумент передается в git merge-base
для определения самого последнего общего коммита между этой веткой и текущей веткой.
Начиная с Git v1.7.10, вы можете просто запустить git rebase
без аргументов, и он найдет точку разветвления и перебазирует ваши локальные изменения в ветке upstream.
Вам нужно настроить ветку upstream, чтобы это работало (т.е. git pull
без аргументов должно работать).
Для более подробной информации смотрите документацию по git rebase:
Если не указан, будут использоваться параметры восходящего потока, сконфигурированные в параметрах branch..remote и branch..merge (подробности см. В git-config[1]), и предполагается опция --fork-point. Если вы в настоящее время не находитесь ни в одной ветви или если текущая ветвь не имеет настроенного восходящего потока, перебазировка будет прервана.
Общее решение (если вы не знаете название вышестоящей ветки):
git rebase -i @{upstream}
Обратите внимание, что если ваш апстрим (вероятно, ветвь отслеживания) обновился с момента последней перебазировки, вы получите новые коммиты из апстрима. Если вы не хотите добавлять новые коммиты, используйте
git rebase -i `git merge-base --all HEAD @{upstream}`
но это немного глоток.
git rebase -i --onto @{u}... @{u}
Интерактивное перебазирование, начиная с единственной точки слияния HEAD и его восходящего потока, включая все коммиты в HEAD, которые не находятся в его восходящем.
Другими словами именно то, что вы хотите.