Git: получить преимущества `git rebase --interactive` для выбора вишни

Я хотел бы иметь возможность сделать это:

git cherry-pick --interactive hash-0..hash-n-1  # fantasy command

и получить тот же рабочий процесс, что и интерактивная rebase: появляется буфер редактора, содержащий:

pick hash-0
pick hash-1
pick hash-2
...
pick hash-n-1

где я могу удалить любые нежелательные коммиты, squash их вместе или edit, чтобы сделать паузу между выборами, чтобы выполнить некоторую ручную фиксацию (например, commit --amend) и все такое.

Обратите внимание на то, что pick интерактивной перестановки таналогично похожа на cherry-pick.

Теперь вышеуказанную операцию можно выполнить, выполнив сначала вишневый выбор, а затем интерактивную перестановку, что неудобно. То есть:

$ git tag old-head  # mark starting point for later rebase
$ git cherry-pick hash-0..hash-n-1    # get everything first
$ git rebase --interactive old-head   # okay now rebase "in-branch" to fix it up

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

Ответы

Ответ 1

Хорошо, понял хороший хак.

Запустите тривиальный rebase --interactive HEAD^ по одному фиксатору в текущей ветке. Вы получаете что-то вроде:

pick 1efd396b * Fixed a bug in frob function

Теперь просто вставьте дополнительные хэши, которые вы хотите выбрать:

pick 1efd396b * Fixed a bug in frob function
pick f01934db * Awesome feature added
pick 6fd109c1 * Refactored the widgets layer
squash 3900fd77 * Refactored the widgets layer s'more

Сохраните и выйдите, и wee: мульт rebase любезно возьмет дополнительный крут, который вы загрузили на его спину, и включит его в текущую ветвь в соответствии с командами.

На самом деле вы можете сделать пустую перезагрузку с помощью:

git rebase --interactive HEAD

вы получаете буфер, содержащий

noop

Вам не нужно удалять это; просто добавьте свои выборы после этого.

Добавление: Чтобы создать списки выбора для этого метода, используйте git log --oneline --reverse from..to, затем обрезайте требуемый вывод и добавьте команды переадресации в каждую строку: pick, squash,...

Ответ 2

Хорошо, следуя предложению Карла Норума, я просмотрел аргумент --onto git rebase.

Вариант использования может быть выполнен таким образом, что является улучшением, хотя все еще связано с несколько чрезмерным количеством шагов.

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

Поток выглядит следующим образом:

# We are originally on "mybranch"
# We create a temp-branch pointing to the last commit to be picked: hash-n-1

$ git checkout -b temp-branch hash-n-1   # create branch at last hash

# Then we rebase from the point before the first hash, onto our original branch

$ git rebase --interactive hash-0^ --onto mybranch

# The above rebase should make "temp-branch" into the very object that
# we want "mybranch" to be. If it looks that way, then all that is left is
# make it so:

$ git checkout mybranch          
$ git reset --hard temp-branch
$ git branch -D temp-branch

git rebase --interactive hash-0^ --onto mybranch использует фиксацию до hash-0 как "восходящий" для rebase, беря все коммиты из текущей ветки (на основе hash-n-1), которые не находятся в восходящем потоке. Эти коммиты, конечно, hash-0 через hash-n-1. Они переустанавливаются на головку mybranch, но текущий temp-branch, который reset --hard отслеживает результат. Поэтому нам просто нужно назначить этот указатель на mybranch и удалить temp-branch.

Это довольно неуклюжий, но устраняет дублируемую вишневую подборку и легко восстанавливается в любое время только с помощью git reset --hard mybranch.

(Может ли это быть улучшено.)

Ответ 3

Возможно, лучший ответ есть, но это может сработать для вас.

git cherry | awk '$0=$2' > cherry.txt
"$EDITOR" cherry.txt
git cherry-pick --stdin < cherry.txt

Пример