Чи можу я видалити комбінат git, але зберегти зміни


1055

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

Тепер, коли я закінчую демонстрацію і повертаюся до роботи над моєю галуззю розвитку, я хотів би зняти "тимчасове зобов'язання", яке я зробив, зберігаючи зміни, які я вніс. Це можливо?


65
Наступний раз:git stash
Метт Бал

51
@MattBall, не обов'язково. Хоча git stashце непоганий інструмент, викидні комісії "незавершеного виробництва" теж є законним пристроєм.
kostix

3
Це чудова ресурсна протока від Github: Як скасувати (майже) що-небудь із Git
Jasonleonhard

9
@MattBall @kostix Так, схована скринька особливо непридатна для "довготривалого" приховування, враховуючи, що це один глобальний стек для всього репо. Я хочу мати змогу приховати зміни на гілці, а потім перейти до інших гілок, робити все, що завгодно, повернутися дні пізніше, не переживаючи, що я, можливо, використовував би git stashякусь іншу гілку тимчасово.
Алек

4
Одне, що варто зазначити, stash- це те, що він повністю локальний і буде схильний до втрати коду внаслідок повторного видалення або відпочинку або відмови або втрати обладнання. IMO, він дійсно повинен використовуватися лише для дуже короткострокових WIP. Любіть WIP-зобов’язання перед відпусткою: P .. називайте це мозковим демпфікуванням!
MοδεMεδιϲ

Відповіді:


1617

Це так просто, як це:

git reset HEAD^

Примітка: деякі оболонки трактуються ^як особливий символ (наприклад, деякі оболонки Windows або ZSH із включеним глобусом ), тому, можливо, доведеться цитувати їх "HEAD^"у цих випадках.

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

Зауважте, що інший варіант - це продовжувати функціонувати як звичайно, а потім на наступній точці фіксування замість цього виконувати:

git commit --amend [-m … etc]

що замість цього буде редагувати останню комісію, маючи той самий ефект, що і вище.

Зауважте, що це (як і майже на кожну відповідь на git) може спричинити проблеми, якщо ви вже підштовхнули погану команду до місця, звідки, можливо, хтось із них витягнув її. Спробуйте уникати цього


47
Це, безумовно, найпростіше, але якщо ви вже перенесли свої зобов'язання на віддалений і хтось інший витягнув його, я б дуже вагався зробити щось, крім вибачення.
atw13

11
@sicophrenic, не пропустіть можливість прочитати "Скинути скинуте" з цього приводу.
kostix

33
Я отримую More?після цього. Що б я не fatal: ambiguous argument 'HEADwhateverItypedIn': unknown revision or path not in the working tree.
набрав

50
@DaAwesomeP здається, що ви використовуєте оболонку, яка розглядає ^як особливий символ. Ви можете або процитувати посилання "HEAD^", або використовувати альтернативний синтаксис без HEAD~1котирування
Гарет

8
Працював для мене, довелося втекти з персонажа, хочаgit reset HEAD\^
cevaris

188

Є два способи впоратися з цим. Що простіше, залежить від вашої ситуації

Скидання

Якщо фіксація, від якої ви хочете позбутися, була останньою, і ви не зробили жодної додаткової роботи, яку ви можете просто використати git-reset

git reset HEAD^

Повертає вашу філію до виконання безпосередньо перед поточною ГОЛОВОЮ. Однак це фактично не змінює файли у вашому робочому дереві. Як результат, зміни, які були в цьому комітеті, відображаються як змінені - це як команда "відключити". Насправді у мене є псевдонім зробити саме це.

git config --global alias.uncommit 'reset HEAD^'

Тоді ви можете просто використовувати git uncommitв майбутньому резервне копіювання одного зобов’язання.

Кабачки

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

git rebase -i <ref>

Я говорю вище, тому що хочу уточнити, що це може бути будь-яка кількість повернень. Запустіть git logі знайдіть зобов’язання, від якого ви хочете позбутися, скопіюйте його SHA1 та використовуйте його замість <ref>. Git переведе вас в режим інтерактивного ребазування. Він покаже всі зобов'язання між вашим поточним станом та тим, що ви поставите замість цього <ref>. Тож якщо <ref>10 комісій назад, це покаже всі 10 комітів.

Перед кожним комітом воно матиме слово pick. Знайдіть зобов’язання, від якого ви хочете позбутися, та змініть його pickна fixupабо squash. Використовуючи fixupпросто відкидання, яке виконує повідомлення, і об'єднує зміни зі своїм безпосереднім попередником у списку. ThesquashКлючове слово робить те ж саме, але дозволяє редагувати повідомлення фіксації на знову поєднанні фіксації.

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

УВАГА:

Випуск змінює історію - НЕ робіть це для будь-яких зобов’язань, якими ви вже поділилися з іншими розробниками.

Шташинг

Надалі, щоб уникнути цієї проблеми, розгляньте можливість використання git stashтимчасово зберігати неприйняті роботи.

git stash save 'some message'

Це дозволить зберегти ваші поточні зміни в бік вашого списку сховищ. Зверху наведена найбільш явна версія команди скриньки, що дозволяє в коментарі описати те, що ви зберігаєте. Ви також можете просто запустити git stashі більше нічого, але жодне повідомлення не зберігатиметься.

Ви можете переглянути свій список сховища за допомогою ...

git stash list

Це покаже вам всі ваші статистичні дані, над якими гілками вони були зроблені, а також повідомлення та на початку кожного рядка та ідентифікатор цього сховища, яке виглядає приблизно так, stash@{#}де # - це його позиція у масиві статей.

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

git stash apply stash@{#}

Знову ж, там # - це позиція в масиві стасів. Якщо сховище, яке ви хочете відновити, знаходиться в 0положенні - тобто, якщо це було останнє сховище. Тоді ви можете просто запустити команду, не вказуючи позицію приховування, git припустить, що ви маєте на увазі останню:git stash apply .

Так, наприклад, якщо я виявлю, що я працюю над неправильною гілкою - я можу виконати наступну послідовність команд.

git stash
git checkout <correct_branch>
git stash apply

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

Сподіваюсь, це допомагає.


6
git config --global alias.uncommit reset HEAD^просто псевдоніми відключити для скидання. Натомість зробітьgit config --global alias.uncommit 'reset HEAD^'
mernst

3
Зауважте, що вам доведеться використовувати ^^ замість ^, якщо ви використовуєте в командному рядку Windows.
Pramod BR

106

Я думаю, ти це шукаєш

git reset --soft HEAD~1

Він скасовує останнє зобов’язання, зберігаючи зміни, внесені до цього зобов'язання, для постановки.


7
Дякую. Це працювало для мене. Якщо зателефонувати git reset HEAD^в Windows, просто з'явиться запит "Більше?" - що б це не означало
Тайрон

12
@Tyron ^- символ втечі в DOS. У поєднанні з новим рядком він служить підказкою для продовження попередньої команди. Введення тексту git reset HEAD^^має працювати в Windows.
trk

40

Так, ви можете видалити свій комітет, не видаляючи зміни: git reset @ ~


7
Це дійсно те, що я хочу, і це буде прийнята відповідь, на мою думку, велике спасибі!
Карлос Лю

2
Цікавий, компактний синтаксис, я раніше не бачив його. Чим це відрізняється від git reset --softабо git reset --keep?
user776686

18

Ви шукаєте або git reset HEAD^ --softабо git reset HEAD^ --mixed.

Існує 3 режими для команди скидання, як зазначено в документах :

git reset HEAD^ --soft

скасувати git commit . Зміни все ще існують у робочому дереві (папка проекту) + індекс (- кеш)

git reset HEAD^ --mixed

скасувати git commit+git add . Зміни все ще існують у робочому дереві

git reset HEAD^ --hard

Як ви ніколи не вносили цих змін до бази даних коду. Зміни відпали від робочого дерева.


9

Для тих, хто використовує zsh, вам доведеться використовувати наступне:

git reset --soft HEAD\^

Пояснено тут: https://github.com/robbyrussell/oh-my-zsh/isissue/449

Якщо URL-адреса стає мертвою, важливою частиною є:

Уникніть ^ у вашій команді

Ви також можете використовувати HEAD ~, так що вам не доведеться уникати цього разу.


15
Я ніколи не можу згадати цю команду, і мені
доведеться погуглювати

2
git reset HEAD^працює в zsh для мене, можливо, було виправлено.
Бен Коля Менслі

@BenKolyaMansley Яку версію zsh ти працюєш?
Грег Хілстон

Я використовуюzsh 5.3 (x86_64-apple-darwin18.0)
Ben Kolya Mansley

7

У моєму випадку я вже підштовхнувся до репо. Ой!

Ви можете скасувати певну комісію, зберігаючи зміни у ваших локальних файлах, виконавши:

git revert -n <sha>

Таким чином я зміг утримати потрібні мені зміни та скасувати зобов’язання, які вже були натиснуті.


У моєму випадку мені потрібно було повернути щось, що я вже перемістив у віддалений сховище. Ще більше ой! Кращий спосіб був git revert bad-commit-sha, то git revert -n revert-commit-just-created-shaі тоді ремонт звідти. Ти отримав мене на півдорозі. Дякую!
TinkerTenorSoftwareGuy

Здається, це робить навпаки, ні? Це створює нові зміни, які відповідають поверненню змін, зроблених у вибраному комітеті. Якщо ви повинні здійснити ці нові зміни, ви скасуєте роботу, яку хотіли фактично зберегти.
svaens

3

Використання git 2.9 (саме 2.9.2.Windows.1) підкаже git reset HEAD^для отримання додаткової інформації; не впевнений, що тут очікується вхід. Нижче див. Знімок екрана

введіть тут опис зображення

Знайшов інше рішення git reset HEAD~#numberOfCommits за допомогою якого ми можемо вибрати кількість місцевих комісій, які ви хочете скинути, зберігаючи зміни недоторканими. Отже, ми отримуємо можливість викинути всі місцеві комісії, а також обмежену кількість місцевих комітетів.

Нижче див. Скріншоти, що відображаються git reset HEAD~1в дії: введіть тут опис зображення

введіть тут опис зображення


Ймовірно, вам потрібно уникнути символу ^ - спробуйте скинути git reset "HEAD ^" або git reset HEAD \ ^
Марк Фішер

Додавши до цього, git reset HEAD ^^ працює як єдиний ^, трактується як новий рядок.
Джон Осс

2

Ще один спосіб зробити це.

Додайте фіксацію у верхній частині тимчасової комісії та виконайте:

git rebase -i

Щоб об'єднати два коміти в один (команда відкриє текстовий файл із явними інструкціями, відредагуйте його).


2
Технічно правильно, але ніде не так елегантно, як просто робити git reset HEAD^. Тут є багато можливостей для помилок Git.
TheBuzzSaw
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.