Як я розбиваю два непослідовні коміти?


183

Я трохи новачок у всій функції випуску в рамках git. Скажімо, я прийняв такі зобов'язання:

A -> B -> C -> D

Згодом я розумію, що Dмістить виправлення, яке залежить від якогось нового коду, який додається A, і що ці комісії належать разом. Як я сквошувати A& Dразом і залишати B& в Cспокої?

Відповіді:


258

Ви можете запустити git rebase --interactiveі змінити порядок D перед B, а D - на А.

Git відкриє редактор, і ви побачите такий файл, наприклад: git rebase --interactive HEAD~4

pick aaaaaaa Commit A
pick bbbbbbb Commit B
pick ccccccc Commit C
pick ddddddd Commit D

# Rebase aaaaaaa..ddddddd onto 1234567 (4 command(s))
#
# 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
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

Тепер ви змінюєте файл, який він виглядає приблизно так:

pick aaaaaaa Commit A
squash ddddddd Commit D
pick bbbbbbb Commit B
pick ccccccc Commit C

І git тепер змішить зміни A і D разом в один комітет, а потім поставить B і C. Якщо ви не хочете зберігати повідомлення D, замість цього squash, ви б використовували fixupключове слово. Щоб дізнатися більше про те fixup, ви можете проконсультуватися з git rebaseдокументами або ознайомитись з цим питанням, яке має хороші відповіді.


5
Спочатку я читав це як "перекидання D на A, скрізь D на A, а потім B на DA". З відповіді незрозуміло, що це можна зробити, упорядкувавши рядки в текстовому редакторі.
Віктор Сергієнко

3
Якщо ваша філія локальна, ви отримаєте There is no tracking information for the current branchпомилку при повторному наданні звіту. В цьому випадку вам необхідно вказати кількість фіксацій ви хочете працювати, як це: git rebase -i HEAD~4. Дивіться цю відповідь .
johndodo

1
Я використовую інтерактивний режим (git rebase -i) роками, я просто зрозумів, що його можна переупорядкувати . Дякую 🤟🏻
CalvinChe

43

Примітка. Ні в якому разі не слід змінювати комітети, які були перенесені на інше репо, якщо ви не знаєте наслідків .

git log --oneline -4

D commit_message_for_D
C commit_message_for_C
B commit_message_for_B
A commit_message_for_A

git rebase --interactive

pick D commit_message_for_D
pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A

Введіть i(Введіть VIM у режим вставки)

Змініть список, щоб він виглядав так (Вам не потрібно видаляти або включати повідомлення про фіксацію). Не помиляйтеся squash! :

pick C commit_message_for_C
pick B commit_message_for_B
pick A commit_message_for_A
squash D

Введіть Escпотім ZZ(Збереження та вихід VIM)

# This is a combination of 2 commits.
# The first commit's message is:

commit_message_for_D

# This is the 2nd commit message:

commit_message_for_A

Тип i

Змініть текст так, як ви хочете виглядати нове повідомлення про фіксацію. Я рекомендую, щоб це був опис змін у фіксації Aта D:

new_commit_message_for_A_and_D

Введіть EscпотімZZ

git log --oneline -4

E new_commit_message_for_A_and_D
C commit_message_for_C
B commit_message_for_B

git show E

(You should see a diff showing a combination of changes from A and D)

Тепер ви створили нову комісію E. Здійснюється Aі Dбільше не входить у вашу історію, але їх уже немає. Ви можете їх відновити в цей момент і на деякий час git rebase --hard D( git rebase --hardзнищить будь-які локальні зміни! ).


3

Для тих, хто використовує SourceTree :

Переконайтесь, що ви ще не переслідували коміти.

  1. Репозиторій> Інтерактивна база даних ...
  2. Перетягніть D (новіший фіксатор), щоб бути безпосередньо над A (старший фіксатор)
  3. Переконайтеся, що фіксація D виділена
  4. Клацніть Squash with previous

1

Інтерактивна база даних працює добре, поки у вас немає філії великої функції з 20-30 комітами та / або парою злиття з головним чи / та виправленням конфліктів, коли ви здійснювали комунікацію у своїй гілці. Навіть з пошуку моїх комітетів через історію та заміни pickна squashне працює тут. Тому я шукав інший шлях і знайшов цю статтю . Я вніс свої зміни, щоб працювати над цим відділенням:

git checkout master
git fetch
git pull
git merge branch-name
git reset origin/master
git branch -D branch-name
git checkout -b branch-name
git add --all
#Do some commit
git push -f --set-upstream origin branch-name

Перед цим я отримав запит на тягу з приблизно ~ 30 комітами з 2-3 злиттями від конфліктів master + fixing. І після цього я отримав чіткий піар з одним зобов’язанням.

PS ось bash скрипт для виконання цих кроків в автоматичній.


Перше рішення в цій статті дуже приємне, спасибі за посилання
Гуді

-1

$ git майстер оформлення замовлення

$ git журнал - лінія

D
C
B
A

$ git rebase - в HEAD ^^^ HEAD ^

$ git журнал - лінія

D
A

Я думаю, ти маєш на увазі --oneline? І схоже, що ви впали, Cі Bце не те, що планувала ОП.
bstpierre

Не працювало для мене. Він перемістив і мою ГОЛОВУ, і господаря вниз, до A, але не злив D у A ( git show A), а D, C і B були втрачені в моєму реєстрі-журналі. Довелося git rebase Dповертатися.
Нат
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.