Как использовать '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. Любые идеи?

65 git
12.12.2008 19:45:16
Пожалуйста, назовите ваш вопрос немного лучше. Возможно, стоит упомянуть, что вы хотите сделать интерактивный перебаз для всех изменений в ветке. Желательно в форме вопроса (хотя и не всегда возможно).
Dustin 12.12.2008 20:58:12
Вы хотите переназначить измененный masterили просто отредактировать только что сделанные вами коммиты test-branch?
DylanYoung 10.11.2017 18:12:23
8 ОТВЕТОВ
РЕШЕНИЕ

Вы пробовали: git rebase -i master?

45
4.05.2015 22:57:04
Это терпит неудачу, если мастер опережает текущую базу слияния в вашей ветви.
Alex Brown 30.08.2012 17:14:29
Проблема в git rebase -i masterтом, что у вас могут возникнуть конфликты слияния, с которыми вы не обязательно хотите иметь дело в данный момент, или вы можете исправить конфликт в одном коммите, только чтобы исправить его снова в другом коммите во время перебазирования. Я добавил ответ, который предоставляет альтернативу этому и альтернативу указанию точного коммита или количества коммитов назад, с которых вы хотите сделать ребазинг.
Seth Flowers 24.06.2015 20:47:34
rerereВаш друг, когда вы отказываетесь.
DylanYoung 10.11.2017 18:01:42
Не работает для меня, это приводит к странным конфликтам слияния после того, как я делаю ... ничего, буквально! Я имею в виду все, что я сделал git rebase master (не -iтолько для тестов) , и это уже приводит к конфликтам.
Hi-Angel 17.09.2018 14:30:47

Используйте gitk (* nix), или gitx (OS X) или аналогичные на других платформах, и посмотрите, какой коммит был корнем вашей ветви. Затем запустите:

git rebase -i <the SHA hash of the root commit>

Например, у меня есть репозиторий, который я проверял с помощью gitx:

Gitx Screencap

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

git rebase -i 38965ed29d89a4136e47b688ca10b522b6bc335f

И мой редактор всплывает с этим, и я могу изменить / squash / что угодно, как мне угодно.

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`~
21
24.04.2018 05:14:17
| catкажется бесполезным использованием кошки, когда вы можете использовать git --no-pager.
Matthieu Moy 5.05.2015 06:06:21
@MatthieuMoy - no-pager, вероятно, отсутствовал в версии, которую я использовал в декабре 2008 года. Этот вариант не попал в полученную кодовую базу до июля 2008 года. Github.com/git/git/commit/…
Otto 5.05.2015 13:27:48
@ Отто, я не заметил дату твоего поста. Вы на самом деле хотели указать на github.com/git/git/commit/…
Matthieu Moy 5.05.2015 14:31:36

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

Эта маленькая команда git называется merge-base. Он берет два коммита и дает вам первого общего предка обоих. Так...

git merge-base feature master

... даст вам первого общего предка этих двух коммитов. Угадайте, что происходит, когда вы передаете этот коммит git rebase -i, например ...

git rebase -i `git merge-base feature master`

Интерактивный ребаз от первого общего предка как основной, так и функциональной ветви. Прибыль! ;)

67
17.11.2010 17:36:31
Хотя это уродливо - нет под рукой синтаксического сахара?
Alex Brown 30.08.2012 17:14:52
Это довольно по сравнению со многими git-решениями :).
studgeek 19.11.2012 06:58:19
Я бы предложил использовать git merge-base master HEADметод, который всегда должен работать для текущей ветви, не вводя имя текущей ветви. Псевдоним этой команды, и у вас есть хорошая команда коротких мерзавцев.
jayeff 25.09.2013 13:19:21
git rebase -i $(git merge-base @{u} HEAD) - это предполагает, что ваша текущая ветвь настроена на отслеживание базовой ветки. Пример: git branch feature1 origin/masterбудет отслеживать происхождение / мастер. Так что теперь вам даже не нужно вводить это.
Alexander Bird 13.05.2016 17:25:34

Общее решение (если вы не знаете название вышестоящей ветки):

git rebase -i @{upstream}

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

git rebase -i `git merge-base --all HEAD @{upstream}`

но это немного глоток.

2
30.08.2012 17:48:56
Я видел предположения, что симметричная разница HEAD ... master (которая дает основание слияния как отрицательный третий sha) может использоваться в git rebase, но я не могу понять, как.
Alex Brown 30.08.2012 17:49:53
git rebase -i --onto @{u}... @{u}

Интерактивное перебазирование, начиная с единственной точки слияния HEAD и его восходящего потока, включая все коммиты в HEAD, которые не находятся в его восходящем.

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

1
23.06.2014 14:36:11
Но если @{u}настроено, то вы можете использовать без аргументов git rebase, смотрите мой ответ.
Matthieu Moy 5.05.2015 06:05:06

Начиная с Git v1.7.10, вы можете просто запустить git rebaseбез аргументов, и он найдет точку разветвления и перебазирует ваши локальные изменения в ветке upstream.

Вам нужно настроить ветку upstream, чтобы это работало (т.е. git pullбез аргументов должно работать).

Для более подробной информации смотрите документацию по git rebase :

Если не указан, будут использоваться параметры восходящего потока, сконфигурированные в параметрах branch..remote и branch..merge (подробнее см. Git-config [1]), и предполагается опция --fork-point. Если вы в настоящее время не находитесь ни в одной ветви или если текущая ветвь не имеет настроенного восходящего потока, перебазировка будет прервана.

4
5.05.2015 06:03:56

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

git rebase -i XYZ

Вы делаете ребаз только начиная со 2-го коммита.

Если вы хотите выполнить ребазинг с первого коммита:

git rebase -i --root
59
29.05.2015 18:25:57
Но «--root» выполняет ребазинг с первого когда-либо сделанного коммита, а не с первого коммита в ветви, о котором просит OP
Chris B 15.02.2016 10:39:34

Проблема с ребазингом из другой ветки

Проблема в 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для определения самого последнего общего коммита между этой веткой и текущей веткой.

7
24.06.2015 20:44:00
Я не уверен, что этот ответ имеет большой смысл с учетом данной топологии. База слияния здесь будет masterв момент test-branchсоздания (скажем 3hgn45). Так что этот ребаз на самом деле ничего не делает. В нем говорится, перебазировать эту ветку с (но не включая) 3hgn45на (и в том числе) HEADна 3hgn45. Но, возможно, я неправильно понимаю ваше предложение ...
DylanYoung 10.11.2017 18:08:04
РЕДАКТИРОВАТЬ: я понимаю; вопрос ОП мне просто не ясен. Вы можете подумать о добавлении предупреждения о том, что это не будет поддерживать изменения master(т. Е. На самом деле это не перебазирование, поскольку вы поддерживаете ту же базу, просто редактируя некоторые коммиты в текущей ветке).
DylanYoung 10.11.2017 18:14:42
@DylanYoung - да, мое понимание вопроса ОП заключалось в том, что на самом деле они не хотели делать ребаз на вершине master, а просто раздавили все коммиты в один, поскольку они расходятся master.
Seth Flowers 13.11.2017 15:32:16
Вот похожий псевдоним «перебазировать общего предка», который допускает дополнительные аргументы:rbca = "!git rebase $(git merge-base HEAD \"$1\") ${@:2} #"
cambunctious 27.10.2018 20:37:14