Как мне использовать '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 rebase -i master?

Хорошо, я предполагаю, что ветка называется "особенность", и она была разветвлена ​​от "мастера".

Эта маленькая команда 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:

Gitx Screencap

Теперь, когда я знаю корневой хэш, я могу запустить это:

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, которые не находятся в его восходящем.

Другими словами именно то, что вы хотите.

Другие вопросы по тегам