Як я можу розділити Git, похований в історії?


292

Я промайнув свою історію і хочу змінити її. Проблема полягає в тому, що у мене є зобов’язання з двома незв'язаними змінами, і це зобов'язання оточене деякими іншими змінами в моїй локальній (не натиснутої) історії.

Я хочу розколоти цю команду, перш ніж я виштовхую її, але більшість посібників, які я бачу, пов'язані з розбиттям вашої останньої комісії або непоміченими локальними змінами. Чи можливо це зробити на зобов'язаннях, які трохи поховані в історії, не маючи з того часу "виконувати" свої зобов'язання?


1
можливий дублікат Split

Відповіді:


450

Існує посібник з розподілу комісій на сторінці оновлення . Швидкий підсумок:

  • Виконайте інтерактивну базу даних, включаючи цільову комісію (наприклад git rebase -i <commit-to-split>^ branch) та позначте її для редагування.

  • Коли ребаза досягне цього зобов’язання, використовуйте git reset HEAD^для скидання до початку фіксації, але збережіть ваше робоче дерево недоторканим.

  • Поступово додайте зміни та виконайте їх, роблячи стільки завдань, скільки бажаєте. add -pможе бути корисно додати лише деякі зміни у заданий файл. Використовуйтеcommit -c ORIG_HEAD якщо ви хочете повторно використовувати оригінальне повідомлення про фіксацію для певного виконання.

  • Якщо ви хочете перевірити, що ви вчиняєте (хороша ідея!), Використовуйте, git stashщоб сховати ту частину, яку ви не скоїли (або stash --keep-indexперед тим, як навіть зробити це), протестуйте,git stash pop поверніть решту на робоче дерево. Продовжуйте робити зобов’язання, поки не будете виконані будь-яких модифікацій, тобто створіть чисте дерево роботи.

  • Запустіть, git rebase --continueщоб перейти до застосування комітетів після розбитої комісії.


17
... але нічого з цього не робити, якщо ви вже підштовхнули історію з часу розколу.
wilhelmtell

29
@wilhelmtell: Я опустив свою звичайну "потенційно небезпечну; див." відновлення після реконструкції "за течією, тому що ОП прямо заявив, що не підштовхував цю історію.
Каскабель

2
і ви досконало прочитали. Я намагався уникнути "котла", коли уточнив, що це ще не поділена історія :) У будь-якому плані я мав успіх з вашою пропозицією. Хоча великі болі робити ці речі після факту, хоча. Тут я засвоїв урок, і саме для того, щоб переконатися, що коміти введені правильно для початку!
Бен

2
Перший крок може бути краще зазначено як git rebase -i <sha1_of_the_commit_to_split>^ branch. І git guiце приємний інструмент для розбиття завдання, який можна використовувати для додавання різних частин файлу в різні коміти.
Цянь Сюй

3
@QiangXu: Перша - розумна пропозиція. Друге саме те, чому я запропонував git add -p, що git guiв цьому відділі можна зробити більше, ніж можна (зокрема, редагування лушпинь, постановка всього, починаючи з поточної лунки, і пошук луків за допомогою регулярного вираження).
Каскабель

3

Ось як це зробити з Магітом .

Скажіть, що потрібно змінити ed417ae; він містить дві непов'язані зміни і закопується під одним або декількома комісіями. Натисніть, llщоб показати журнал, і перейдіть до ed417ae:

початковий журнал

Потім натисніть, rщоб відкрити спливаюче вікно бази даних

спливаюче вікно бази даних

а mтакож змінити команду в пункті.

Зверніть увагу на те, як @зараз існує команда, яку ви хочете розділити - це означає, що HEAD зараз на цьому виконує:

зміна комітету

Ми хочемо перенести HEAD до батьківського, тому перейдіть до батьківського (47e18b3) та натисніть x( magit-reset-quicklyприв’язаний, oякщо ви використовуєте evil-magit) та введіть, щоб сказати "так, я мав на увазі здійснення в точці". Тепер ваш журнал повинен виглядати так:

журнал після скидання

Тепер натисніть qкнопку , щоб перейти до звичайного статусу Magit, а потім скористайтеся командою regular untage, uщоб відміняти те, що не йде в першому фіксації c, виконайте решту як завжди, а потім sвідмітьте та cопустіть те, що відбувається у другому фіксації, і коли це зроблено: натисніть, rщоб відкрити спливаюче вікно бази даних

спливаюче вікно бази даних

і ще один, rщоб продовжувати, і ви закінчили! llтепер показує:

весь готовий журнал


1

Щоб розділити <commit>команду та додати нову комісію до цього та зберегти дату автора <commit>, - кроки наступні:

  1. Відредагуйте фіксацію раніше <commit>

    git rebase -i <commit>^^
    

    NB: можливо, це також знадобиться для редагування <commit>.

  2. Вишневий вибір <commit>в індекс

    git cherry-pick -n <commit>
    
  3. Інтерактивно скинути непотрібні зміни з індексу та скинути робоче дерево

    git reset -p && git checkout-index -f -a
    

    Як альтернатива, просто заховайте непотрібні зміни інтерактивно: git stash push -p -m "tmp other changes"

  4. Внесіть інші зміни (якщо такі є) та створіть нову комісію

    git commit -m "upd something" .
    

    За бажанням повторіть пункти 2-4, щоб додати більше проміжних комісій.

  5. Продовжуйте випуск

    git rebase --continue
    

0

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

  1. Використовуйте свій редактор і видаліть рядки, з яких потрібно витягнути the_file. Закрити the_file. Це єдине вам потрібне видання, все інше - це лише команди git.
  2. Етап видалення в індексі:

    git  add  the_file
    
  3. Відновіть тільки що видалені рядки назад у файл, не впливаючи на індекс !

    git show HEAD:./the_file > the_file
    
  4. "SHA1" - це команда, з якої потрібно витягнути рядки з:

    git commit -m 'fixup! SHA1' 
    
  5. Створіть друге, абсолютно нове зобов’язання із вмістом для вилучення, відновленим за кроком 3:

    git commit -m 'second and new commit' the_file 
    
  6. Не редагуйте, не зупиняйте та не продовжуйте - просто прийміть усе:

    git rebase --autosquash -i SHA1~1
    

Звичайно, навіть швидше, коли зобов'язання витягти з нього є останнє зобов'язання:

4. git commit -C HEAD --amend
5. git commit -m 'second and new commit' thefile
6. no rebase, nothing

Якщо ви користуєтесь, magitто кроки 4, 5 та 6 - це одна дія: Виконувати, миттєве виправлення


-2

Якщо ви ще не натиснули, просто використовуйте git rebase. Ще краще використовувати git rebase -iінтерактивний рух для переміщень. Ви можете перенести зловмисну ​​комісію на передню частину, а потім розділити її як завгодно і перемістити патчі назад (якщо потрібно).


14
Не потрібно переміщати його куди завгодно. Розділіть його там, де є.
Каскабель

1
На жаль, це не працює для мене, оскільки частина історії після фіксації залежить від неї, тому я трохи обмежений. Однак це був би мій перший вибір.
Бен

@Ben: це нормально - зобов’язання після цього взагалі не потрібно змінювати (припускаючи, що ви зберігаєте всі зміни, а не викидаєте деякі з них). Більше інформації тут - stackoverflow.com/questions/1440050/…
Ефір
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.