Як розділити останній комітет на два в 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.