Як розділити останній комітет на два в Git


277

У мене є дві робочі гілки, майстер і форум, і я щойно вніс деякі зміни у галузь форуму , які я хотів би перебрати в майстер . Але, на жаль, комісія, яку я хочу вишнево вибрати, також містить деякі модифікації, які я не хочу.

Рішенням, ймовірно, було б якось видалити неправильну команду та замінити її двома окремими комітами, одним із змінами, які я хочу вибрати в master, та іншими, які там не належать.

Я намагався робити

git reset --hard HEAD^

який видалив усі зміни, тому мені довелося повернутися

git reset ORIG_HEAD

Отже, моє запитання полягає в тому, що найкращий спосіб розділити останню комісію на два окремих комітети?

Відповіді:


332

Вам слід використовувати індекс. Зробивши змішане скидання (" git reset HEAD ^"), додайте в індекс перший набір змін, а потім виконайте їх. Потім зробіть решту.

Ви можете використовувати " git add ", щоб внести всі зміни, внесені у файл до індексу. Якщо ви не хочете поетапно проводити будь-які зміни, внесені у файл, лише деякі з них, ви можете використовувати "git add -p".

Подивимось приклад. Припустимо, у мене був файл з назвою myfile, який містить такий текст:

something
something else
something again

Я змінив його в останньому фіксації, щоб тепер він виглядав так:

1
something
something else
something again
2

Тепер я вирішую, що хочу розділити його на два, і я хочу, щоб вставка першого рядка була в першому коміті, а вставка останнього рядка - у другому.

Спочатку я повертаюся до батьківського HEAD, але хочу зберегти зміни у файловій системі, тому я використовую "git reset" без аргументів (що дозволить зробити так званий "змішаний" скидання):

$ git reset HEAD^
myfile: locally modified
$ cat myfile
1
something
something else
something again
2

Тепер я використовую "git add -p", щоб додати зміни, які хочу ввести в індекс (= я їх статую). "git add -p" - це інтерактивний інструмент, який запитує вас про те, які зміни у файлі слід додати до індексу.

$ git add -p myfile
diff --git a/myfile b/myfile
index 93db4cb..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,5 @@
+1
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,s,e,?]? s    # split this section into two!
Split into 2 hunks.
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? y  # yes, I want to stage this
@@ -1,3 +2,4 @@
 something
 something else
 something again
+2
Stage this hunk [y,n,a,d,/,K,g,e,?]? n   # no, I don't want to stage this

Тоді я здійснюю цю першу зміну:

$ git commit -m "Added first line"
[master cef3d4e] Added first line
 1 files changed, 1 insertions(+), 0 deletions(-)

Тепер я можу вчинити всі інші зміни (а саме цифру "2", поставлену в останньому рядку):

$ git commit -am "Added last line"
[master 5e284e6] Added last line
 1 files changed, 1 insertions(+), 0 deletions(-)

Давайте перевіримо журнал, щоб побачити, що ми маємо:

$ git log -p -n2 | cat
Commit 5e284e652f5e05a47ad8883d9f59ed9817be59d8
Author: ...
Date: ...

    Added last line

Diff --git a/myfile b/myfile
Index f9e1a67..2f113ce 100644
--- a/myfile
+++ b/myfile
@@ -2,3 +2,4 @@
 something
 something else
 something again
+2

Commit cef3d4e0298dd5d279a911440bb72d39410e7898
Author: ...
Date: ...

    Added first line

Diff --git a/myfile b/myfile
Index 93db4cb..f9e1a67 100644
--- a/myfile
+++ b/myfile
@@ -1,3 +1,4 @@
+1
 something
 something else
 something again

1
Я повільно звикав до того, що я випробовував Mercurial протягом останніх півтора тижнів, і є зручна команда швидкого доступу, git reset [--patch|-p] <commit>яку ви можете використати, щоб врятувати вам проблеми git add -pпісля скидання. Маю рацію? Використання git 1.7.9.5.
— trojjer

2
Ось трохи більше про цю техніку, в тому числі і перебазування , якщо він був старше зробити, або вам потрібно змінити N фіксації на М фіксації: emmanuelbernard.com/blog/2014/04/14 / ... .
— Кріс Вестін

84

Цілі:

  • Я хочу розділити минулу комісію ( splitme) на дві частини.
  • Я хочу підтримувати повідомлення про фіксацію .

План:

  1. інтерактивна база даних від попереднього splitme.
  2. редагувати splitme.
  3. Скиньте файли, щоб вони розділилися на другу комісію
  4. Змінюйте зобов’язання, зберігаючи повідомлення, змінюйте у міру необхідності.
  5. Додайте назад файли, розділені з першого коміксу.
  6. Зверніться до нового повідомлення.
  7. Продовжити базу даних.

Етапи перезавантаження (1 і 7) можуть бути пропущені, якщо splitmeце остання комісія.

git rebase -i splitme^
# mark splitme commit with 'e'
git reset HEAD^ -- $files
git commit --amend
git add $files
git commit -m "commit with just some files"
git rebase --continue

Якби я хотів, щоб спочатку були зроблені розділені файли, я знову повторюю -i і перемикаю порядок

git rebase -i splitme^
# swap order of splitme and 'just some files'

1
git reset HEAD^була відсутнім фрагментом головоломки. Також добре працює -p. Дякую!
— Маріус Гедмінас

10
Важливо відзначити -- $filesаргумент до git reset. З пропущеними шляхами git resetвідновлює ці файли до стану посилаються на комісію, але не змінює жодних комітів. Якщо ви залишите шляхи, ви "втратите" зобов'язання, яке хочете змінити на наступному кроці.
— дуелінові маркери

2
Цей спосіб заважає вам знову копіювати та вставляти перше повідомлення про фіксацію порівняно з прийнятою відповіддю.
— Кальвін

Також: якщо ви хочете скинути всі файли, просто скористайтеся git reset HEAD^ -- .. Надзвичайно дивно, що це не зовсім поведінка git reset HEAD^.
— allidoiswin

52

Щоб змінити поточну комісію на два коміти, ви можете зробити щось на кшталт наступного.

Або:

git reset --soft HEAD^

Це скасовує останнє виконання, але залишає все інсценованим. Потім можна видалити певні файли:

git reset -- file.file

Необов’язково перезавантажте частини цих файлів:

git add -p file.file

Зробіть нове перше зобов’язання:

git commit

Виконайте етап і вкажіть інші зміни в другому комітті:

git commit -a

Або:

Скасуйте та видаліть усі зміни від останнього комітету:

git reset HEAD^

Вибірковий етап першого етапу змін:

git add -p

Виконувати:

git commit

Зробіть решту змін:

git commit -a

(На будь-якому кроці, якщо ви скасуєте комісію, яка додала абсолютно новий файл, і хочете додати це до другого комітету, вам доведеться додати його вручну як commit -aлише поетапні зміни до вже відстежуваних файлів.)


22

Run git gui, виберіть радіокнопку «Змінити останній Комміт» і прибрати з буфера (Commit> прибрати з буфера З Commit, або Ctrl- U) зміни , які ви не хочете йти в перший Ком. Я думаю, що це найпростіший шлях для цього.

Інша річ, яку ви можете зробити, - це вишня змінити вибору, не виконуючи ( git cherry-pick -n), а потім або вручну, або з git guiвибраними потрібними змінами перед вчиненням.



13

Я здивований, що ніхто не запропонував git cherry-pick -n forum. Це дозволить поетапно змінити зміни від останньої forumфіксації, але не здійснити їх - ви зможете resetусунути необхідні вам зміни та здійснити те, що ви хочете зберегти.


3

Метод подвійного повернення-сквош

  1. Зробіть ще одну фіксацію, яка видаляє небажані зміни. (Якщо це файл, це справді просто: git checkout HEAD~1 -- files with unwanted changesі git commit. Якщо ні, файли зі змішаними змінами можуть бути частково поетапними git reset fileі git add -p fileяк проміжний крок.) Назвіть це відновлення .
  2. git revert HEAD- Зробіть ще одне зобов’язання, яке додасть небажані зміни. Це подвійне повернення
  3. З 2-х комітетів, які ви зробили зараз, накладіть перший на поділ ( git rebase -i HEAD~3). Тепер це зобов’язання стає вільним від небажаних змін, оскільки вони є у другому.

Переваги

  • Зберігає повідомлення про фіксацію
  • Працює, навіть якщо зобов’язання розколотись не останнє. Потрібно лише, щоб небажані зміни не суперечили пізнім завданням

1

Оскільки ви збираєте вишню, ви можете:

  1. cherry-pickйого з --no-commitопцією додано.
  2. resetі використання add --patch, add --editабо просто addна стадії , що ви хочете зберегти.
  3. commit поетапні зміни.
    • Щоб повторно використовувати оригінальне повідомлення про фіксацію, ви можете додати в команду --reuse-message=<old-commit-ref>або --reedit-message=<old-commit-ref>параметри commit.
  4. Зніміть нестандартні зміни за допомогою reset --hard.

Інший спосіб, збереження чи редагування вихідного повідомлення про фіксацію:

  1. cherry-pick оригінальний фіксатор як звичайний.
  2. Зніміть зміни, які ви не хочете, і використовуйте addдля поетапної зміни.
    • Цей крок буде легким, якщо ви видаляєте додане вами, але трохи складним, якщо ви додаєте те, що ви видалили, або скасуєте зміни.
  3. commit --amend щоб змінити обертання на вишню.
    • Ви знову отримаєте те саме повідомлення про фіксацію, яке ви можете зберегти або переглянути за необхідності.

0

Це може бути ще одним рішенням, орієнтованим на випадки, коли існує величезна комісія, і невелику кількість файлів потрібно перенести в новий комітет. Це буде спрацьовувати, якщо набір <path>файлів потрібно витягнути з останнього комітету в HEAD і всі перемістити до нового комітету. Якщо потрібно декілька комітетів, можна використовувати інші рішення.

Спочатку зробіть виправлення у поетапні та нестандартні області, які міститимуть зміни для повернення коду до модифікації та після модифікації відповідно:

git reset HEAD^ <path>

$ git status
On branch <your-branch>
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   <path>

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        modified:   <path>

Щоб зрозуміти, що буде (стрілка та коментарі не входять до команди):

git diff --cached   -> show staged changes to revert <path> to before HEAD
git diff            -> show unstaged changes to add current <path> changes

Скасувати <path>зміни в останній комісії:

git commit --amend  -> reverts changes on HEAD by amending with staged changes

Створіть новий комітет із <path>змінами:

git commit -a -m "New Commit" -> adds new commit with unstaged changes

Це призводить до створення нового комітету, що містить зміни, вилучені з останнього комітету.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.