git rebase -i <any earlier commit>, Это отображает список коммитов в настроенном текстовом редакторе.
Найдите коммит, который вы хотите вставить после (допустим, это a1b2c3d). В редакторе измените эту строку pickна edit.
Начните перебазирование, закрыв текстовый редактор (сохраните изменения). Это оставляет вас в командной строке с фиксацией, которую вы выбрали ранее ( a1b2c3d), как если бы она была только что зафиксирована .
Внесите свои изменения и git commit( НЕ исправляя, в отличие от большинства edits). Это создает новый коммит после того, который вы выбрали.
git rebase --continue, Это воспроизводит последовательные коммиты, оставляя ваш новый коммит вставленным в правильное место.
Помните, что это перепишет историю и сломает любого, кто попытается вытащить.
Это добавило новую фиксацию после фиксации, которая находится после той, на которую я выполнял перезагрузку (также последней фиксации), а не сразу после той, на которую я выполнял перезагрузку. Результат был таким же, как если бы я просто сделал новый коммит в конце с изменениями, которые я хотел вставить. Моя история стала A -- B -- C -- Dвместо желанной A -- D -- B -- C.
XedinUnknown
2
@XedinUnknown: Значит, вы неправильно использовали Rebase.
SLaks
3
Теперь Dкоммит может быть где угодно. Предположим, у нас есть A - B - Cи у нас есть коммит, Dкоторого даже нет в этой ветке. Мы знаем его SHA, однако можем git rebase -i HEAD~3. Теперь между Aи Bpickлиниями, мы вставляем новуюpick линию , которая говорит pick SHA, что дает хэш желаемого D. Это не обязательно должен быть полный хэш, только сокращенный. git rebase -iпросто вишня выбирает все коммиты, перечисленные pickстроками в буфере; они не обязательно должны быть оригинальными, перечисленными для вас.
Kaz
1
@Kaz Это похоже на другой правильный ответ.
BartoszKP
3
Еще проще, вы можете использовать breakключевое слово в редакторе в отдельной строке между двумя фиксациями (или в первой строке, чтобы вставить фиксацию перед указанной фиксацией).
SimonT
30
Оказывается, довольно просто, ответ нашел здесь . Предположим, вы на ветке branch. Выполните следующие шаги:
создайте временную ветвь из фиксации после того, как вы захотите вставить новую фиксацию (в данном случае фиксацию A):
git checkout -b temp A
выполнить изменения и зафиксировать их, создав коммит, назовем его N:
git commit -a -m "Message"
(или git addсопровождаемый git commit)
перебазируйте коммиты, которые вы хотите иметь после нового коммита (в данном случае коммитов Bи C) на новый коммит:
Я не мог следовать принятому ответу SLaks, но это сработало для меня. После того, как я получил нужную историю коммитов, мне пришлось git push --forceизменить удаленное репо.
escapecharacter
1
При использовании rebase с параметром -Xtheirs конфликты автоматически разрешаются автоматически, поэтому git rebase temp branch -Xtheirs. Полезный ответ для внедрения в скрипт!
David C
Для таких новичков, как я, я хотел бы добавить это после git rebase temp branch, но до того git branch -d temp, как все, что вам нужно сделать, это исправить и обработать конфликты и проблемы слияния git rebase --continue, т.е. не нужно ничего фиксировать и т.д.
Пагсли,
19
Еще более простое решение:
Создайте новый коммит в конце D. Теперь у вас есть:
A -- B -- C -- D
Затем запустите:
$ git rebase -i hash-of-A
Git откроет ваш редактор, и он будет выглядеть так:
pick 8668d21 B
pick 650f1fc C
pick 74096b9 D
Просто переместите D наверх, затем сохраните и выйдите
Хорошая идея, однако может быть сложно ввести D на C, когда вы намереваетесь написать эти изменения. А.
BartoszKP
У меня есть ситуация, когда у меня есть 3 коммита, которые я хочу перебазировать вместе, и коммит в середине, который не связан. Очень приятно иметь возможность просто переместить этот коммит раньше или позже вниз по строке коммитов.
раскрывается
13
Предполагая, что история фиксации есть preA -- A -- B -- C, если вы хотите вставить фиксацию между Aи B, шаги следующие:
git rebase -i hash-of-preA
Git откроет ваш редактор. Контенту может понравиться это:
pick 8668d21 A
pick 650f1fc B
pick 74096b9 C
Измените первое pickна edit:
edit 8668d21 A
pick 650f1fc B
pick 74096b9 C
Сохранить и выйти.
Измените свой код, а затем git add . && git commit -m "I"
git rebase --continue
Теперь ваша история коммитов Git preA -- A -- I -- B -- C
Если вы столкнетесь с конфликтом, Git остановится на этой фиксации. Вы можете использовать git diffдля поиска маркеров конфликтов и их разрешения. После разрешения всех конфликтов вам нужно использовать, git add <filename>чтобы сообщить Git, что конфликт разрешен, а затем перезапустить git rebase --continue.
Если вы хотите отменить перебазирование, используйте git rebase --abort.
Вот стратегия, которая позволяет избежать «взлома редактирования» во время перебазирования, которое можно увидеть в других ответах, которые я читал.
Используя, git rebase -iвы получаете список коммитов с момента этого коммита. Просто добавьте «разрыв» вверху файла, это приведет к прерыванию перебазирования в этой точке.
После запуска git rebaseтеперь остановится в точке «разрыва». Теперь вы можете редактировать свои файлы и создавать коммит в обычном режиме. Затем вы можете продолжить перебазирование с помощью git rebase --continue. Это может вызвать конфликты, которые вам придется исправить. Если вы заблудились, не забывайте, что вы всегда можете прервать использование git rebase --abort.
Эту стратегию можно обобщить, чтобы вставить фиксацию где угодно, просто поместите «разрыв» в то место, где вы хотите вставить фиксацию.
Переписав историю, не забудьте git push -f. Применяются обычные предупреждения о том, что другие люди скачивают вашу ветку.
Извините, но мне сложно понять, как это «избежать перебазирования». Вы здесь бежите rebase. Нет большой разницы, создадите ли вы фиксацию во время перебазирования или заранее.
BartoszKP
Уупс, я имел в виду избегать "хака редактирования" во время перебазирования, наверное, я сформулировал это плохо.
аксерологементы 06
Правильно. В моем ответе также не используется функция «редактирования» перебазирования. Тем не менее, это еще один действенный подход - спасибо! :-)
BartoszKP 07
Это, безусловно, лучшее решение!
Теодор Р. Смит
6
Здесь уже много хороших ответов. Я просто хотел добавить решение «без перебазирования» за 4 простых шага.
Резюме
git checkout A
git commit -am "Message for commit D"
git cherry-pick A..C
git branch -f master HEAD
объяснение
(Примечание: одним из преимуществ этого решения является то, что вы не касаетесь своей ветки до последнего шага, когда вы на 100% уверены, что у вас все в порядке с конечным результатом, поэтому у вас есть очень удобный шаг «предварительного подтверждения» с учетом AB-тестирования .)
Исходное состояние (я предположил masterдля вашего имени ветки)
A -- B -- C <<< master <<< HEAD
1) Начните с направления ГОЛОВКИ в нужное место
git checkout A
B -- C <<< master
/
A <<< detached HEAD
(При желании здесь, вместо того, чтобы отсоединять HEAD, мы могли бы создать временную ветку, с git checkout -b temp Aкоторой нам нужно будет удалить в конце процесса. Оба варианта работают, делайте так, как вы предпочитаете, поскольку все остальное остается прежним)
2) Создайте новый коммит D для вставки
# at this point, make the changes you wanted to insert between A and B, then
git commit -am "Message for commit D"
B -- C <<< master
/
A -- D <<< detached HEAD (or <<< temp <<< HEAD)
3) Затем принесите копии последних отсутствующих коммитов B и C (была бы такая же строка, если бы было больше коммитов)
git cherry-pick A..C
# (if any, resolve any potential conflicts between D and these last commits)
B -- C <<< master
/
A -- D -- B' -- C' <<< detached HEAD (or <<< temp <<< HEAD)
(удобное AB-тестирование здесь, если необходимо)
Настал момент проверить ваш код, протестировать все, что нужно протестировать, и вы также можете сравнить / сравнить / проверить, что у вас было и что вы получите после операций.
4) В зависимости от ваших тестов между Cи C', либо нормально, либо нокаут.
(ЛИБО) 4-ОК) Наконец, переместите ссылкуmaster
git branch -f master HEAD
B -- C <<< (B and C are candidates for garbage collection)
/
A -- D -- B' -- C' <<< master
(ИЛИ) 4-КО) Просто оставьте masterбез изменений
Если вы создали временную ветку, просто удалите ее с помощью git branch -d <name>, но если вы выбрали отдельный маршрут HEAD, никаких действий на этом этапе не требуется, новые коммиты будут иметь право на сборку мусора сразу после того, как вы повторно подключитесь HEADс помощьюgit checkout master
В обоих случаях (OK или KO) на этом этапе просто произведите проверку еще masterраз, чтобы повторно подключиться HEAD.
Ответы:
Это даже проще, чем в ответе OP.
git rebase -i <any earlier commit>
, Это отображает список коммитов в настроенном текстовом редакторе.a1b2c3d
). В редакторе измените эту строкуpick
наedit
.a1b2c3d
), как если бы она была только что зафиксирована .git commit
( НЕ исправляя, в отличие от большинстваedit
s). Это создает новый коммит после того, который вы выбрали.git rebase --continue
, Это воспроизводит последовательные коммиты, оставляя ваш новый коммит вставленным в правильное место.Помните, что это перепишет историю и сломает любого, кто попытается вытащить.
источник
A -- B -- C -- D
вместо желаннойA -- D -- B -- C
.D
коммит может быть где угодно. Предположим, у нас естьA - B - C
и у нас есть коммит,D
которого даже нет в этой ветке. Мы знаем его SHA, однако можемgit rebase -i HEAD~3
. Теперь междуA
иB
pick
линиями, мы вставляем новуюpick
линию , которая говоритpick SHA
, что дает хэш желаемогоD
. Это не обязательно должен быть полный хэш, только сокращенный.git rebase -i
просто вишня выбирает все коммиты, перечисленныеpick
строками в буфере; они не обязательно должны быть оригинальными, перечисленными для вас.break
ключевое слово в редакторе в отдельной строке между двумя фиксациями (или в первой строке, чтобы вставить фиксацию перед указанной фиксацией).Оказывается, довольно просто, ответ нашел здесь . Предположим, вы на ветке
branch
. Выполните следующие шаги:создайте временную ветвь из фиксации после того, как вы захотите вставить новую фиксацию (в данном случае фиксацию
A
):выполнить изменения и зафиксировать их, создав коммит, назовем его
N
:(или
git add
сопровождаемыйgit commit
)перебазируйте коммиты, которые вы хотите иметь после нового коммита (в данном случае коммитов
B
иC
) на новый коммит:(возможно , вам нужно использовать ,
-p
чтобы сохранить слияния, если таковые были - благодаря более уже не существующий комментарий по ciekawy )удалите временную ветку:
После этого история выглядит следующим образом:
Конечно, возможны конфликты при перебазировании.
Если ваша ветка не является локальной, это приведет только к перезаписи истории, что может вызвать серьезные проблемы.
источник
git push --force
изменить удаленное репо.git rebase temp branch -Xtheirs
. Полезный ответ для внедрения в скрипт!git rebase temp branch
, но до тогоgit branch -d temp
, как все, что вам нужно сделать, это исправить и обработать конфликты и проблемы слиянияgit rebase --continue
, т.е. не нужно ничего фиксировать и т.д.Еще более простое решение:
Создайте новый коммит в конце D. Теперь у вас есть:
Затем запустите:
Git откроет ваш редактор, и он будет выглядеть так:
Просто переместите D наверх, затем сохраните и выйдите
Теперь у вас будет:
источник
Предполагая, что история фиксации есть
preA -- A -- B -- C
, если вы хотите вставить фиксацию междуA
иB
, шаги следующие:git rebase -i hash-of-preA
Git откроет ваш редактор. Контенту может понравиться это:
Измените первое
pick
наedit
:Сохранить и выйти.
Измените свой код, а затем
git add . && git commit -m "I"
git rebase --continue
Теперь ваша история коммитов Git
preA -- A -- I -- B -- C
Если вы столкнетесь с конфликтом, Git остановится на этой фиксации. Вы можете использовать
git diff
для поиска маркеров конфликтов и их разрешения. После разрешения всех конфликтов вам нужно использовать,git add <filename>
чтобы сообщить Git, что конфликт разрешен, а затем перезапуститьgit rebase --continue
.Если вы хотите отменить перебазирование, используйте
git rebase --abort
.источник
Вот стратегия, которая позволяет избежать «взлома редактирования» во время перебазирования, которое можно увидеть в других ответах, которые я читал.
Используя,
git rebase -i
вы получаете список коммитов с момента этого коммита. Просто добавьте «разрыв» вверху файла, это приведет к прерыванию перебазирования в этой точке.После запуска
git rebase
теперь остановится в точке «разрыва». Теперь вы можете редактировать свои файлы и создавать коммит в обычном режиме. Затем вы можете продолжить перебазирование с помощьюgit rebase --continue
. Это может вызвать конфликты, которые вам придется исправить. Если вы заблудились, не забывайте, что вы всегда можете прервать использованиеgit rebase --abort
.Эту стратегию можно обобщить, чтобы вставить фиксацию где угодно, просто поместите «разрыв» в то место, где вы хотите вставить фиксацию.
Переписав историю, не забудьте
git push -f
. Применяются обычные предупреждения о том, что другие люди скачивают вашу ветку.источник
rebase
. Нет большой разницы, создадите ли вы фиксацию во время перебазирования или заранее.Здесь уже много хороших ответов. Я просто хотел добавить решение «без перебазирования» за 4 простых шага.
Резюме
объяснение
(Примечание: одним из преимуществ этого решения является то, что вы не касаетесь своей ветки до последнего шага, когда вы на 100% уверены, что у вас все в порядке с конечным результатом, поэтому у вас есть очень удобный шаг «предварительного подтверждения» с учетом AB-тестирования .)
Исходное состояние (я предположил
master
для вашего имени ветки)1) Начните с направления ГОЛОВКИ в нужное место
(При желании здесь, вместо того, чтобы отсоединять HEAD, мы могли бы создать временную ветку, с
git checkout -b temp A
которой нам нужно будет удалить в конце процесса. Оба варианта работают, делайте так, как вы предпочитаете, поскольку все остальное остается прежним)2) Создайте новый коммит D для вставки
3) Затем принесите копии последних отсутствующих коммитов B и C (была бы такая же строка, если бы было больше коммитов)
(удобное AB-тестирование здесь, если необходимо)
Настал момент проверить ваш код, протестировать все, что нужно протестировать, и вы также можете сравнить / сравнить / проверить, что у вас было и что вы получите после операций.
4) В зависимости от ваших тестов между
C
иC'
, либо нормально, либо нокаут.(ЛИБО) 4-ОК) Наконец, переместите ссылку
master
(ИЛИ) 4-КО) Просто оставьте
master
без измененийЕсли вы создали временную ветку, просто удалите ее с помощью
git branch -d <name>
, но если вы выбрали отдельный маршрут HEAD, никаких действий на этом этапе не требуется, новые коммиты будут иметь право на сборку мусора сразу после того, как вы повторно подключитесьHEAD
с помощьюgit checkout master
В обоих случаях (OK или KO) на этом этапе просто произведите проверку еще
master
раз, чтобы повторно подключитьсяHEAD
.источник