Vraag Hoe een opgegeven commit in git te wijzigen?


Ik dien meestal een lijst met commits in ter beoordeling. Als ik heb:

  • HEAD 
  • Commit3 
  • Commit2 
  • Commit1

Ik weet dat ik head commit kan aanpassen met git commit --amend, maar hoe kan ik wijzigen Commit1, aangezien het niet de HEAD begaan?


1700
2017-07-27 05:19


oorsprong


antwoorden:


Je kunt git rebase gebruiken, bijvoorbeeld, als je wilt modificeren om opnieuw te committen bbc643cd, rennen

$ git rebase --interactive 'bbc643cd^'

Wijzig in de standaardeditor pick naar edit in de regel waarvan u de commit wilt wijzigen. Breng uw wijzigingen aan en verbind ze vervolgens met hetzelfde bericht dat u eerder had:

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

om de commit te wijzigen, en daarna

$ git rebase --continue

om terug te keren naar de vorige hoofd commit.

WAARSCHUWING: Merk op dat dit de SHA-1 van die commit zal veranderen evenals alle kinderen - met andere woorden, dit herschrijft de geschiedenis vanaf dat moment. Je kunt repos breken door dit te doen als je op drukt met het commando git push --force


2232
2017-07-27 05:28



Gebruik de geweldige interactieve rebase:

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

Zoek de commit die je wilt, verander pick naar e (edit) en sla het bestand op en sluit het. Git zal terugspoelen naar die commit, zodat je:

  • gebruik git commit --amend om wijzigingen aan te brengen, of
  • gebruik git reset @~ om de laatste commit te verwijderen, maar niet de wijzigingen in de bestanden (dat wil zeggen, je naar het punt brengen waar je was toen je de bestanden had bewerkt, maar je nog niet had vastgelegd).

Dit laatste is handig voor het doen van complexere dingen zoals het splitsen in meerdere commits.

Ren dan git rebase --continueen Git herhaalt de daaropvolgende wijzigingen bovenop je aangepaste commit. Mogelijk wordt u gevraagd om een ​​aantal samenvoegconflicten op te lossen.

Notitie: @ is steno voor HEAD, en ~ is de commit voor de opgegeven commit.

Lees meer over geschiedenis herschrijven in de Git-documenten.


Wees niet bang om te rebasen

ProTip: wees niet bang om te experimenteren met "gevaarlijke" opdrachten die de geschiedenis herschrijven * - Git verwijdert uw commits niet standaard gedurende 90 dagen; je kunt ze vinden in de reflog:

$ 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

* Pas op voor opties zoals --hard en --force hoewel - ze kunnen gegevens weggooien.
* Schrap ook de geschiedenis niet op takken waar je aan meewerkt.



Op veel systemen git rebase -i opent Vim standaard. Vim werkt niet zoals de meeste moderne teksteditors, dus kijk eens naar hoe je rebase met behulp van Vim. Als u liever een andere editor gebruikt, wijzig deze dan met git config --global core.editor your-favorite-text-editor.


304
2018-04-29 17:50



Interactieve rebase met --autosquash is iets dat ik vaak gebruik wanneer ik eerdere commits dieper in de geschiedenis wil herstellen. Het versnelt in wezen het proces dat ZelluX's antwoord illustreert, en is vooral handig als je meer dan één commit hebt die je moet bewerken.

Uit de documentatie:

--autosquash

Wanneer het commit-logbericht begint met "squash! ..." (of "fixup! ..."), en er is een commit waarvan de titel begint met dezelfde ..., wijzig dan automatisch de todo-lijst van rebase -i zodat de commit gemarkeerd voor squashen komt direct na de commit die moet worden aangepast

Stel dat je een geschiedenis hebt die er als volgt uitziet:

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

en je hebt wijzigingen die je wilt wijzigen in Commit2 en voer vervolgens je wijzigingen in met behulp van

$ git commit -m "fixup! Commit2"

alternatief kun je de commit-sha gebruiken in plaats van het commit-bericht, dus "fixup! e8adec4 of zelfs slechts een voorvoegsel van het commit-bericht.

Start vervolgens een interactieve rebase op de commit eerder

$ git rebase e8adec4^ -i --autosquash

je editor zal openen met de commits die al correct zijn geordend

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

het enige dat u hoeft te doen, is opslaan en afsluiten


57
2017-09-29 17:59



Rennen:

$ git rebase --interactive commit_hash^

elk ^ geeft aan hoeveel teruggaven u wilt bewerken, als het slechts één commit is (de commit-hash die u hebt opgegeven), dan voegt u er gewoon een toe ^.

Met Vim verander je de woorden pick naar reword voor de commits die je wilt wijzigen, opslaan en afsluiten (:wq). Dan zal git je elke commit vragen die je hebt gemarkeerd als reword, zodat je het commit-bericht kunt wijzigen.

Elk commit-bericht dat u moet opslaan en afsluiten (:wq) om naar het volgende commit-bericht te gaan

Als u wilt afsluiten zonder de wijzigingen toe te passen, drukt u op :q!

BEWERK: om in te navigeren vim je gebruikt j omhoog gaan, k naar beneden gaan, h om naar links te gaan, en l om naar rechts te gaan (dit alles in NORMAL modus, druk op ESC gaan naar NORMAL modus). Druk op om een ​​tekst te bewerken i zodat je de INSERT modus, waar u tekst invoegt. druk op ESC terug gaan naar NORMAL modus :)

BIJWERKEN: Hier is een geweldige link vanuit de github-lijst Hoe (bijna) alles met git ongedaan te maken 


30
2017-07-02 19:11



Als je om wat voor reden dan ook niet van interactieve editors houdt, kun je gebruiken git rebase --onto.

Stel dat je wilt wijzigen Commit1. Ten eerste, vertakking van voor  Commit1:

git checkout -b amending [commit before Commit1]

Ten tweede, grijp Commit1 met cherry-pick:

git cherry-pick Commit1

Pas nu uw wijzigingen aan, creëer Commit1':

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

En ten slotte, nadat je alle andere wijzigingen hebt opgeslagen, transplanteer je de rest van je commits master bovenop je nieuwe commit:

git rebase --onto amending Commit1 master

Lezen: "rebase, op de tak amending, alle commits tussen Commit1 (niet-inclusief) en master (inclusief) ". Dat wil zeggen, Commit2 en Commit3, waardoor de oude Commit1 volledig wordt geknipt. Je zou ze gewoon kunnen uitkiezen, maar deze manier is eenvoudiger.

Vergeet niet om je takken op te ruimen!

git branch -d amending

12
2017-10-22 12:19



Kwam tot deze benadering (en het is waarschijnlijk precies hetzelfde als het gebruik van interactieve rebase) maar voor mij is het nogal rechtlijnig.

Opmerking: ik presenteer deze aanpak ter illustratie van wat u kunt doen in plaats van een alledaags alternatief. Omdat het vele stappen heeft (en mogelijk enkele voorbehouden.)

Stel dat je commit wilt veranderen 0 en je bent momenteel bezig feature-branch

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

Ga naar deze commit en maak een quick-branch. U kunt ook uw featuretak klonen als een herstelpunt (voordat u begint).

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

Je hebt nu zoiets als dit:

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

Veranderingen in het toneel, alle andere dingen opbergen.

git add ./example.txt
git stash

Wijzigingen doorvoeren en afrekenen naar feature-branch

git commit --amend
git checkout feature-branch

Je hebt nu zoiets als dit:

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

rebase feature-branch naar quick-branch (los eventuele conflicten op tijdens de reis). Stash aanbrengen en verwijderen quick-branch.

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

En je eindigt met:

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

Git zal niet dupliceren (hoewel ik niet echt kan zeggen in welke mate) de 0 commit bij rebasen.

Opmerking: alle commit-hashes worden gewijzigd vanaf de commit die we oorspronkelijk wilden veranderen.


6
2018-06-01 11:57



Om een ​​niet-interactieve opdracht te krijgen, plaatst u een script met deze inhoud in uw 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"

Gebruik het door uw veranderingen te organiseren (met git add) en voer dan uit git fixup <commit-to-modify>. Natuurlijk zal het nog steeds interactief zijn als je conflicten krijgt.


4
2018-01-16 15:27



Volledig niet-interactief commando(1)

Ik dacht dat ik een alias zou delen die ik hiervoor gebruik. Het is gebaseerd op niet-interactieve interactieve rebase. Om het toe te voegen aan je git, voer je deze opdracht uit (onderstaande uitleg):

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'

Het grootste voordeel van deze opdracht is het feit dat het is no-vim.


(1)aangezien er geen conflicten zijn tijdens rebase, natuurlijk

Gebruik

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

De naam amend-to lijkt geschikt IMHO. Vergelijk de stroom met --amend:

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

Uitleg

  • git config --global alias.<NAME> '!<COMMAND>' - maakt een globale git alias genaamd <NAME> die niet-git commando zal uitvoeren <COMMAND>
  • f() { <BODY> }; f - een "anonieme" bash-functie.
  • SHA=`git rev-parse "$1"`; - converteert het argument naar git-revisie en wijst het resultaat toe aan de variabele SHA
  • git commit --fixup "$SHA" - fixup-commit voor SHA. Zien git-commit docs
  • GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
    • git rebase --interactive "$SHA^" deel is bedekt door andere antwoorden.
    • --autosquash is wat wordt gebruikt in combinatie met git commit --fixup, zien git-rebase docs voor meer informatie
    • GIT_SEQUENCE_EDITOR=true is wat het geheel niet-interactief maakt. Deze hack heb ik geleerd van deze blogpost.

4
2018-02-27 01:47



Voor mij was het voor het verwijderen van een aantal referenties van een repo. Ik heb geprobeerd rebasen en liep tegen een ton schijnbaar ongerelateerde conflicten aan tijdens het rebasen - ga verder. Probeer niet zelf te rebasen, gebruik de tool genaamd BFG (brew install bfg) op mac.


1
2017-11-07 07:24



Ik heb dit opgelost,

1) door nieuwe commit te maken met wijzigingen die ik wil ..

r8gs4r commit 0

2) ik weet welke commit ik nodig heb om ermee te fuseren. wat commit 3 is.

zo, git rebase -i HEAD~4 # 4 staat voor 4 recente commit (hier staat commit 3 op de 4e plaats)

3) in interactieve rebase bevindt de recente commit zich onderaan. het zal er hetzelfde uitzien,

pick q6ade6 commit 3
pick vr43de commit 2
pick ac123d commit 1
pick r8gs4r commit 0

4) hier moeten we commit herschikken als je wilt fuseren met een specifieke commit. het zou moeten zijn,

parent
|_child

pick q6ade6 commit 3
f r8gs4r commit 0
pick vr43de commit 2
pick ac123d commit 1

na het herschikken moet je het vervangen p  pick met f (fixup zal samenvoegen zonder commit bericht) of s (squash samenvoegen met commit-bericht kan tijdens runtime veranderen)

en bewaar dan je boom.

nu samenvoegen gedaan met bestaande commit.

Opmerking: het is niet de voorkeur methode, tenzij u onderhoudt op uw eigen. als   je hebt een grote teamgrootte, het is geen acceptabele methode om git te herschrijven   boom zal eindigen in conflicten waarvan je weet dat andere gewoon niet. als je wil   om je boom schoon te houden met minder commits kan dit proberen en als het is   klein team anders heeft het niet de voorkeur .....


1
2018-01-05 18:35



Gebaseerd op Documentatie

Het bericht van oudere of meerdere commit-berichten wijzigen

git rebase -i HEAD~3 

Het bovenstaande toont een lijst van de laatste 3 commits op de huidige branch, verander 3 naar iets anders als je meer wilt. De lijst ziet er ongeveer als volgt uit:

pick e499d89 Delete CNAME
pick 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Vervangen plukken met met andere woorden uitdrukken vóór elk commit-bericht dat u wilt wijzigen. Laat je zeggen dat je de tweede commit in de lijst verandert, je bestand zal er als volgt uitzien:

pick e499d89 Delete CNAME
reword 0c39034 Better README
pick f7fde4a Change the commit message but push the same commit.

Sla het commit-lijstbestand op en sluit het, dit zal een nieuwe editor voor je openen om je commit-bericht te veranderen, het commit-bericht te veranderen en op te slaan.

Forceer tot slot de gewijzigde commits.

git push --force

0
2018-05-17 08:38