Переупорядочение фиксаций

Я в настоящее время работаю над ответвлением и хочу, некоторые передают для слияния в другие ответвления:

    a-b-c-d-e-f-g (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)
   \
    x-x-x-x-x (branchB)

(Буквы обозначают фиксации, и "x" являются несоответствующими фиксациями.)

Однако я заметил, что это будет хорошая идея объединить некоторые фиксации. Я хочу "связать" фиксацию a, d, e и g в один патч и передать его ведущему устройству. Фиксации b и f должны перейти как одна фиксация к branchB. Существует ли хороший ''-выход мерзавца способ достигнуть его?

81
задан ntc2 5 June 2012 в 02:51
поделиться

3 ответа

git rebase --interactive - это нужная вам команда.

Пример:

Текущий статус таков:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git status
On branch master
nothing to commit, working tree clean
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
a6e3c6a (HEAD -> master) Fourth commit
9a24b81 Third commit
7bdfb68 Second commit
186d1e0 First commit

Я хочу изменить порядок коммитов 9a24b81 (Третья фиксация) и 7bdfb68 (Вторая фиксация). Для этого я сначала нахожу фиксацию перед первой фиксацией, которую мы хотим изменить . Это фиксация 186d1e0 (первая фиксация).

Выполняемая команда git rebase --interactive COMMIT-BEFORE-FIRST-COMMIT-WE-WANT-TO-CHANGE , в данном случае:

bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git rebase --interactive 186d1e0

Это открывает файл по умолчанию редактор со следующим содержимым:

pick 7bdfb68 Second commit
pick 9a24b81 Third commit
pick a6e3c6a Fourth commit

# Rebase 186d1e0..a6e3c6a onto 186d1e0 (3 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

Обратите внимание, что порядок коммитов в файле противоположен тому, который используется для журнала git. В журнале git самая последняя фиксация находится вверху. В этом файле самая последняя фиксация находится внизу.

Как объясняется в комментарии внизу файла, я могу делать разные вещи, например, сжимать, отбрасывать и переупорядочивать коммиты. Чтобы изменить порядок коммитов, я редактирую файл так, чтобы он выглядел следующим образом (нижние комментарии не отображаются):

pick 9a24b81 Third commit
pick 7bdfb68 Second commit
pick a6e3c6a Fourth commit

Команда pick в начале каждой строки означает «использовать (т.е. включить) эту фиксацию "и когда я сохраняю временный файл с командами rebase и выхожу из редактора, git выполнит команды и обновит репозиторий и рабочий каталог:

$ git rebase --interactive 186d1e0
Successfully rebased and updated refs/heads/master.
bernt@le3180:~/src/stackoverflow/reordering_of_commits
$ git log --oneline
ba48fc9 (HEAD -> master) Fourth commit
119639c Second commit
9716581 Third commit
186d1e0 First commit

Обратите внимание на перезаписанную историю фиксации.

Ссылки:

3
ответ дан 24 November 2019 в 09:41
поделиться

git rebase - это то, что вам нужно. Обратите внимание на опцию --interactive.

0
ответ дан 24 November 2019 в 09:41
поделиться

Команда, которую вы ищете, это git rebase, особенно опция -i/--interactive.

Я буду считать, что вы хотите оставить коммит c на ветке A, и что вы действительно хотите переместить другие коммиты на другие ветки, а не слить их, поскольку слияние - это просто. Давайте начнём с манипуляций с веткой A.

git rebase -i <SHA1 of commit a>^ branchA

Символ ^ означает предыдущий коммит, поэтому эта команда говорит о перебазировании ветки A, используя коммит перед "a" в качестве базового. Git представит вам список коммитов в этом диапазоне. Упорядочьте их и скажите git'у удалять соответствующие коммиты:

pick c ...
pick a ...
squash d ...
squash e ...
squash g ...
pick b
squash f

Теперь история должна выглядеть так:

    c - [a+d+e+g] - [b+f] (branchA)
   /
--o-x-x-x-x-x-x-x-x-x-x (master)

Теперь давайте возьмём только что удалённый коммит b+f для ветки B.

git checkout branchB
git cherry-pick branchA  # cherry-pick one commit, the tip of branchA

И то же самое для a+d+e+g для master:

git checkout master
git cherry-pick branchA^

Наконец, обновите branchA так, чтобы он указывал на c:

git branch -f branchA branchA^^

Теперь у нас должно быть:

    c (branch A) - [a+d+e+g] - [b+f] (dangling commits)
   /
--o-x-x-x-x-x-x-x-x-x-x-[a+d+e+g] (master)
   \
    x-x-x-x-x-[b+f] (branchB)

Обратите внимание, что если у вас есть несколько коммитов, которые вы хотите переместить между ветками, вы можете снова использовать rebase (не интерактивно):

# create a temporary branch
git branch fromAtoB branchA
# move branchA back two commits
git branch -f branchA branchA~2
# rebase those two commits onto branchB
git rebase --onto branchB branchA fromAtoB
# merge (fast-forward) these into branchB
git checkout branchB
git merge fromAtoB
# clean up
git branch -d fromAtoB

Наконец, отказ от ответственности: вполне возможно изменить порядок коммитов таким образом, что некоторые больше не будут применяться чисто. Это может произойти потому, что вы выбрали неудачный порядок (поставили патч перед коммитом, вводящим исправленную функцию); в этом случае вам нужно прервать ребазинг (git rebase --abort). В противном случае вам придётся грамотно исправить конфликты (так же, как вы делаете это при конфликтах слияния), добавить исправления, а затем выполнить git rebase --continue, чтобы двигаться дальше. Эти инструкции также содержатся в сообщении об ошибке, выводимом при возникновении конфликта.

105
ответ дан 24 November 2019 в 09:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: