Питання Як змінити вказану команду в git?


Я зазвичай представляю список зобов'язань для розгляду. Якщо я маю:

  • HEAD 
  • Commit3 
  • Commit2 
  • Commit1

Я знаю, що можу модифікувати голови з допомогою git commit --amend, але як я можу змінити Commit1, з огляду на те, що це не є HEAD вчинити


1704
2017-07-27 05:19


походження


Подивіться альтернативну відповідь тут: stackoverflow.com/a/18150592/520567 Ваша прийнята відповідь насправді є точною відповіддю на ваше запитання, але якщо ви зробили нове завдання готове, перш ніж приймати рішення про використання редагування, ця відповідь буде більш прозорою. Він також може працювати з кількома завданнями, які ви хочете об'єднати / сквош разом із старшим. - akostadinov
Також ви можете просто побачити Розбиття фіксації в Git Tools - переписування історії для отримання додаткової інформації. - hakre
Можливі дублікати Як змінити існуючі, невикористані копії? - tkruse


Відповіді:


Ви можете використовувати git rebase, наприклад, якщо ви хочете змінити назад, щоб здійснити bbc643cdбіжи

$ git rebase --interactive 'bbc643cd^'

У редакторі за замовчуванням змініть pick до edit в рядку, чию комбінацію ви хочете змінити. Зробіть свої зміни, а потім зробіть їх тим самим повідомленням, яке ви мали раніше:

$ git commit --all --amend --no-edit

змінити фіксацію, а після цього

$ git rebase --continue

повернути назад до попередньої голови фіксації.

УВАГА: Зверніть увагу, що це змінить SHA-1 цього зобов'язання як і всі діти - іншими словами, це переписує історію з цього моменту вперед. Ви можете зламати репо, роблячи це якщо ви натискаєте, використовуючи команду git push --force


2240
2017-07-27 05:28



Ще один цікавий варіант у цьому потоці, як тільки ви перейшли на зобов'язання, яке ви хочете змінити, замість того, щоб змінювати файли та передавати їх у верхній частині (той, який ви редагуєте), ви можете поділити цю фіксацію на дві різні повноваження (або навіть більше). У такому випадку поверніться до зобов'язання редагувати і запустіть "git reset HEAD ^". що поставить модифіковані файли цього компромісу на сцену. Тепер вибирайте і фіксуйте будь-які файли за вашим бажанням. Цей потік досить добре пояснюється на сторінці "git-rebase". Див. Розділ "Роздроблення". bit.ly/d50w1M - Diego Pino
У Git 1.6.6 і новіші ви можете скористатись reword дія в git rebase -i замість edit (він автоматично відкриває редактор і продовжує роботу з іншими етапами переробки, що усуває використання git commit --ammend і git rebase --continue коли вам потрібно лише змінити повідомлення, а не вміст). - Chris Johnsen
Після запуску "git rebase hash ^ --interactive", після позначення редагування у commit, "git commit --amend" просто показує повідомлення commit, а не фактичний код. Як я можу змінити код, який був здійснений? Дякую! - mikemaccana
Варто відзначити, що вам може знадобитися запустити git stash раніше git rebase і git stash pop потім, якщо у вас є очікувані зміни. - user123444555621
Зверніть увагу, що з більш новим GIT, було б мудріше слідувати швидким вказівкам, а не сліпо використати git commit --all --amend --no-edit тут Все, що я повинен був зробити після git rebase -i ... було git commit --amend як правило, тоді git rebase --continue. - Eric Chen


Використовуйте дивовижний інтерактивний ребаз:

git rebase -i @~9   # Show the last 9 commits in a text editor

Знайдіть потрібне завдання, змініть pick до e (edit), а потім збережіть і закрийте файл. Gіt буде перемотати до цього завдання, що дозволить вам:

  • використовувати git commit --amend внести зміни, або
  • використовувати git reset @~ щоб відмовитися від останньої фіксації, але не до змін у файлах (тобто до того моменту, коли ви редагували файли, але ще не зробили цього).

Останнє корисно для виконання більш складних речей, таких як розбиття на кілька зобов'язань.

Потім біжи git rebase --continue, і Gіt буде повторювати наступні зміни на вершині вашої модифікованої фіксації. Вас можуть попросити вирішити деякі конфлікти злиття.

Примітка: @ це скорочення для HEAD, і ~ це здійснення до вказаної фіксації.

Докладніше про Переписування історії в документах Git.


Не бійся перебазувати

ProTip: не бійтеся експериментувати з "небезпечними" командами, які перезаписують історію * - за замовчуванням Git не видаляє ваші зобов'язання протягом 90 днів; ви можете знайти їх у блозі:

$ git reset @~3   # go back 3 commits
$ git reflog
c4f708b HEAD@{0}: reset: moving to @~3
2c52489 HEAD@{1}: commit: more changes
4a5246d HEAD@{2}: commit: make important changes
e8571e4 HEAD@{3}: commit: make some changes
... earlier commits ...
$ git reset 2c52489
... and you're back where you started

* Слідкуйте за такими варіантами, як --hard і --force хоча - вони можуть відкинути дані.
* Також не переписуйте історію в усіх галузях, з якими ви співпрацюєте.



На багатьох системах git rebase -i за замовчуванням відкриє Vim. Vim не працює, як більшість сучасних текстових редакторів, тому подивіться на це як перебазировать, використовуючи Vim. Якщо ви хочете використовувати інший редактор, змініть його git config --global core.editor your-favorite-text-editor.


304
2018-04-29 17:50



Середина вашої відповіді - це дивне місце, щоб поставити те, що я можу описати лише як мініатюру для VIM. Це не має значення для питання і просто зачіпає вашу відповідь. - Intentss
@ Intentss: Ага, я бачу, чому це виглядало дивно. Обгрунтування цього полягає в тому, що Vim є текстовим редактором за замовчуванням на багатьох системах, тому перший досвід інтерактивного перезавантаження багатьох людей - це екран, де натискання клацає лівою кнопкою миші по всьому місцю. Потім вони перемикають свого редактора на щось інше, а другий досвід інтерактивного перезавантаження є досить нормальним, але залишає їх цікаво, чому він використовує текстовий файл замість GUI. Щоб досягти потоку з переробкою, вам потрібно щось подібне до Vim, або режим reabase в Emacs. - Zaz
Якщо мені довелося використовувати щось на зразок Gedit або nano для інтерактивного перебудови, я б перебазувати набагато менше. Може бути, це не буде настільки поганою справою, як я трохи прихильник ребаза. - Zaz
Гаразд. Бачачи, як багато людей вважають цю частину невідповідною, я згорнула її до трьох рядків, а також пояснила, як змінити редактор, якщо це потрібно. - Zaz
Чудово! Я не знав, що ти міг би скористатися @ як скорочення для HEAD. Дякуємо за публікацію цього. - James Ko


Інтерактивний переробляти з --autosquash це те, що я часто користуюся, коли мені потрібно виправити попередні дії, що відбуваються в історії. Це суттєво прискорює процес, про який свідчить відповідь ZelluX, і це особливо зручно, коли потрібно виконати кілька дій, необхідних для редагування.

З документації:

--autosquash

Коли повідомлення журналу фіксації починається з "squash! ..." (або "fixup! ..."), і є фікс, чий титул починається з того самого ..., автоматично змінювати список todo перезавантаження -i, щоб commit Позначений для стискання відбувається одразу після того, як зобов'язання буде змінено

Припустимо, у вас є історія, яка виглядає так:

$ git log --graph --oneline
* b42d293 Commit3
* e8adec4 Commit2
* faaf19f Commit1

і у вас є зміни, які ви хочете внести до Commit2, а потім внесіть зміни за допомогою

$ git commit -m "fixup! Commit2"

або ви можете скористатися commit-sha замість повідомлення commit, так що "fixup! e8adec4 або навіть просто префікс повідомлення про порушення.

Тоді ініціюйте інтерактивну ребазу про здійснення раніше

$ git rebase e8adec4^ -i --autosquash

ваш редактор відкриється завдяки вже правильним замовленням

pick e8adec4 Commit2
fixup 54e1a99 fixup! Commit2
pick b42d293 Commit3

все що вам потрібно зробити, це зберегти та вийти


57
2017-09-29 17:59



Ви також можете використовувати git commit --fixup=@~ замість git commit -m "fixup! Commit2". Це особливо корисно, коли повідомлення про вашу передачу тривають довше, і це буде біль, коли ви введете все це. - Zaz


Виконати:

$ git rebase --interactive commit_hash^

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

Використовуючи Vim, ви змінюєте слова pick до reword за зобов'язання, які ви хочете змінити, зберегти та вийти (:wq) Тоді git запропонує вам кожен фікс, який ви позначили як перевизначення, щоб ви могли змінити повідомлення про фінансування.

Кожне повідомлення про порушення, яке потрібно зберегти та вийти (:wq), щоб перейти до наступного повідомлення про фінансування

Якщо ви хочете вийти без застосування змін, натисніть :q!

РЕДАГУВАТИ: для навігації vim ти використовуєш j піднятися k спуститися h піти ліворуч і l йти правильно (все це в Росії NORMAL режим, натисніть ESC піти до NORMAL режим) Щоб відредагувати текст, натисніть i так що ви входите в INSERT режим, де ви вставляєте текст. Прес ESC повернутися до NORMAL режим :)

UPDATE: Ось відмінне посилання з переліку github Як відмінити (майже) що-небудь з GIT 


30
2017-07-02 19:11



Працював прекрасно для мене. Варто згадати git push --force? - u01jmg3
Що git push --force робить перезаписати пульти здійснює ваші місцеві повноваження. Це не випадок цієї теми :) - betoharres
@BetuUuUu, звичайно, якщо ваші зобов'язання виштовхуються на віддалене місце, і ви змінили коректне повідомлення локально, ви б хотіли примусово натиснути на віддалений, чи не так? - Sudip Bhandari
@SudipBhandari Це почуття, яке я отримую. Я не змушував, і тепер у мене є додаткова гілка, яка відбиває всі віддачі тому, хто змінив це повідомлення, що є надто потворним. - ruffin
Інтерактивна ребаза може здатися складною на початку. Я написав пост (з картинками), який докладно представляє, крок за кроком: blog.tratif.com/2018/04/19/the-power-of-git-interactive-rebase - Tomasz Kaczmarzyk


Якщо з якихось причин вам не подобаються інтерактивні редактори, ви можете використовувати git rebase --onto.

Скажімо, ви хочете змінити Commit1. Спочатку гілка від раніше  Commit1:

git checkout -b amending [commit before Commit1]

По-друге, захопити Commit1 з cherry-pick:

git cherry-pick Commit1

Тепер внесіть зміни, створюючи Commit1':

git add ...
git commit --amend -m "new message for Commit1"

І, нарешті, після припинення будь-яких інших змін, трансплантація решти ваших зобов'язує вас master на вершині твого нові зобов'язання:

git rebase --onto amending Commit1 master

Прочитайте: "перемістіть, на гілку" amending, всі зобов'язуються між собою Commit1 (не включено) і master (включно) ". Тобто, Commit2 і Commit3, цілком зрізали старі Commit1. Можна просто вишнево вибрати їх, але це легше.

Не забудьте очистити свої гілки!

git branch -d amending

12
2017-10-22 12:19



ви можете використовувати git checkout -b amending Commit1~1 щоб отримати попереднє зобов'язання - Arin Taylor


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

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

Скажімо, ви хочете змінити зобов'язання 0 і ви зараз перебуваєте feature-branch

some-commit---0---1---2---(feature-branch)HEAD

Оформити замовлення на цю фіксацію та створити a quick-branch. Ви також можете клонувати гілку вашої функції як точку відновлення (перед початком).

?(git checkout -b feature-branch-backup)
git checkout 0
git checkout -b quick-branch

Тепер ви маєте щось на зразок цього:

0(quick-branch)HEAD---1---2---(feature-branch)

Зміни стадії, приховати все інше.

git add ./example.txt
git stash

Здійснити зміни та перевірити назад feature-branch

git commit --amend
git checkout feature-branch

Тепер ви маєте щось на зразок цього:

some-commit---0---1---2---(feature-branch)HEAD
           \
             ---0'(quick-branch)

Перезавантажити feature-branch на quick-branch (вирішити будь-які конфлікти на цьому шляху). Застосувати прилип і видалити quick-branch.

git rebase quick-branch
git stash pop
git branch -D quick-branch

І ви в кінцевому підсумку:

some-commit---0'---1'---2'---HEAD(feature-branch)

Git не буде дублювати (хоча я і не можу сказати, наскільки) 0 здійснити при перезавантаженні.

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


6
2018-06-01 11:57





Щоб отримати неінтерактивну команду, додайте сценарій із цим вмістом у свій PATH:

#!/bin/sh
#
# git-fixup
# Use staged changes to modify a specified commit
set -e
cmt=$(git rev-parse $1)
git commit --fixup="$cmt"
GIT_EDITOR=true git rebase -i --autosquash "$cmt~1"

Використовуйте його, встановлюючи свої зміни (з git add), а потім запустіть git fixup <commit-to-modify>. Звичайно, він все одно буде інтерактивним, якщо ви отримаєте конфлікти.


4
2018-01-16 15:27



Це добре працює. Я додав додаткову функціональність, щоб зробити послідовні виправлення брудного дерева для удосконалення коду. `dirtydiff = $ (git diff); якщо ["$ {dirtydiff}"! = ""]; потім відлуння "Stashing брудне дерево"> & 2; git stash; fi; - Simon Feltman


Повністю неінтерактивна команда(1)

Я просто думав, що поділився псевдонімом, який я використовую для цього. Вона заснована на неінтерактивний інтерактивний ребаз. Щоб додати його до вашого git, запустіть цю команду (пояснення наведено нижче):

git config --global alias.amend-to '!f() { SHA=`git rev-parse "$1"`; git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"; }; f'

Найбільшою перевагою цієї команди є те, що це є ні-вім.


(1)з огляду на те, що під час перебудови немає конфліктів, звичайно

Використання

git amend-to <REV> # e.g.
git amend-to HEAD~1
git amend-to aaaa1111

Ім'я amend-to здається відповідним ІМХО. Порівняйте потік з --amend:

git add . && git commit --amend --no-edit
# vs
git add . && git amend-to <REV>

Пояснення

  • git config --global alias.<NAME> '!<COMMAND>' - створює глобальний псевдонім git <NAME> що буде виконувати команду non-git <COMMAND>
  • f() { <BODY> }; f - "анонімна" функція bash.
  • SHA=`git rev-parse "$1"`; - перетворює аргумент на версію git і присвоює результат змінній SHA
  • git commit --fixup "$SHA" - fixup-commit для SHA. Побачити git-commit документи
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" частина була покрита іншими відповідями.
    • --autosquash це те, що використовується разом з git commit --fixup, побачити git-rebase документи для отримання додаткової інформації
    • GIT_SEQUENCE_EDITOR=true це те, що робить все це неінтерактивним. Це руйнування я дізнався з цього блогу.

4
2018-02-27 01:47



Також можна зробити amend-to обробляти нестаціонарні файли: git config --global alias.amend-to '!f() { SHA=git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f' - Dethariel
Я використовую його --autostash прапор на команді rebase. - idanp