Een git-rebase ongedaan maken

Weet iemand hoe je gemakkelijk een git-rebase ongedaan kunt maken?

De enige manier die in je opkomt is om het handmatig te doen:

  • git check de ouder van de commit voor beide takken uit
  • maak dan een tijdelijke branch vanaf daar
  • pluk alle commits handmatig uit
  • vervang de branch waarin ik heb gerebaseerd door de handmatig aangemaakte branch

In mijn huidige situatie gaat dit werken omdat ik gemakkelijk commits van beide branches kan zien (de ene was mijn spullen, de andere was die van mijn collega).

Mijn aanpak lijkt me echter suboptimaal en foutgevoelig (laten we zeggen dat ik zojuist had gerebaseerd met 2 van mijn eigen branches).

Enig idee?

Verduidelijking: ik heb het over een rebase waarin een aantal commits opnieuw werden afgespeeld. Niet slechts één.


Antwoord 1, autoriteit 100%

De gemakkelijkste manier zou zijn om de head-commit van de branch te vinden zoals deze was direct voordat de rebase begon in de reflog

git reflog

en om de huidige branch ernaar te resetten (met de gebruikelijke kanttekeningen om absoluut zeker te zijn voordat je reset met de optie --hard).

Stel dat de oude commit HEAD@{5} was in het ref log:

git reset --hard HEAD@{5}

In Windows moet u mogelijk de referentie citeren:

git reset --hard "HEAD@{5}"

Je kunt de geschiedenis van het kandidaat-oude hoofd controleren door gewoon een git log HEAD@{5} te doen (Windows: git log "HEAD@{5}").

Als je reflogs per branch niet hebt uitgeschakeld, zou je gewoon git reflog branchname@{1} moeten kunnen doen, aangezien een rebase de branch-kop losmaakt voordat hij weer aan de laatste head wordt bevestigd. Ik zou dit echter dubbel controleren, aangezien ik dit niet recentelijk heb geverifieerd.

Standaard worden alle reflogs geactiveerd voor niet-bare repositories:

[core]
    logAllRefUpdates = true

Antwoord 2, autoriteit 34%

Eigenlijk slaat rebase uw startpunt op in ORIG_HEAD, dus dit is meestal zo eenvoudig als:

git reset --hard ORIG_HEAD

De reset, rebase en merge slaan echter allemaal je originele HEAD-aanwijzer op in ORIG_HEAD dus als je een van die commando’s hebt gedaan sinds de rebase die je ongedaan wilt maken, dan moet je de reflog gebruiken.


Antwoord 3, autoriteit 9%

Het antwoord van Charles werkt, maar misschien wilt u dit doen:

git rebase --abort

om op te ruimen na de reset.

Anders krijgt u mogelijk het bericht Interactive rebase already started .


Antwoord 4, autoriteit 2%

Het resetten van de branch naar het bungelende commit object van zijn oude tip is natuurlijk de beste oplossing, omdat het de vorige staat herstelt zonder enige moeite. Maar als je die commits bent kwijtgeraakt (bijvoorbeeld omdat je in de tussentijd je repository hebt weggegooid, of dit een nieuwe kloon is), kun je de branch altijd opnieuw rebasen. De sleutel hiervoor is de schakelaar --onto.

Stel dat je een onderwerpbranch had met de fantasierijke naam topic, die je aftakelde van master toen de tip van master de 0deadbeef commit. Op een bepaald moment in de topic branch, heb je git rebase master gedaan. Nu wil je dit ongedaan maken. Hier is hoe:

git rebase --onto 0deadbeef master topic

Hiermee worden alle commits op topic die niet op master staan, opnieuw afgespeeld bovenop 0deadbeef.

Met --onto kun je je geschiedenis herschikken in vrijwel elke vorm.

Veel plezier. 🙂


Antwoord 5, autoriteit 2%

In het geval je je branch naar een externe repository had gepusht (meestal de oorsprong) en dan heb je een succesvolle rebase gedaan (zonder merge) (git rebase --abort geeft “Geen rebase bezig”) die je gemakkelijk kunt vertakking resetten met
commando:

git reset –hard origin/{branchName}

Voorbeeld:

$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is ahead of 'origin/{branchName}' by 135 commits.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean
$ ~/work/projects/{ProjectName} $ git reset --hard origin/{branchName}
HEAD is now at 6df5719 "Commit message".
$ ~/work/projects/{ProjectName} $ git status
On branch {branchName}
Your branch is up-to-date with 'origin/{branchName}.
nothing to commit, working directory clean

Antwoord 6

Ik plaats eigenlijk een back-uptag op de vertakking voordat ik een niet-triviale bewerking doe (de meeste rebases zijn triviaal, maar ik zou dat doen als het ergens complex lijkt).

Herstellen is dan net zo eenvoudig als git reset --hard BACKUP.


Antwoord 7

Het gebruik van reflog werkte niet voor mij.

Wat voor mij werkte, was vergelijkbaar met zoals beschreven hier. Open het bestand in .git/logs/refs genoemd naar de branch die werd gerebaseerd en zoek de regel die “rebase finsihed” bevat, zoiets als:

5fce6b51 88552c8f Kris Leech <[email protected]> 1329744625 +0000  rebase finished: refs/heads/integrate onto 9e460878

Bekijk de tweede commit die op de regel wordt vermeld.

git checkout 88552c8f

Toen ik bevestigde dat dit mijn verloren wijzigingen bevatte, vertakt ik me en slaakte een zucht van verlichting.

git log
git checkout -b lost_changes

Antwoord 8

git reset --hard origin/{branchName}

is de juiste oplossing om al uw lokale wijzigingen door rebase te resetten.


Antwoord 9

Voor meerdere commits, onthoud dat elke commit verwijst naar de hele geschiedenis voorafgaand aan die commit. Dus lees in het antwoord van Charles “de oude commit” als “de nieuwste van de oude commits”. Als je reset naar die commit, zal de hele geschiedenis voorafgaand aan die commit opnieuw verschijnen. Dit zou moeten doen wat je wilt.


Antwoord 10

Na de oplossing van @Allan en @Zearin zou ik willen dat ik gewoon een opmerking kon maken, maar ik heb niet genoeg reputatie, dus heb ik de volgende opdracht gebruikt:

In plaats van git rebase -i --abort te doen (let op de -i) moest ik gewoon git rebase --abort doen (zonder de -i).

Als je tegelijkertijd -i en --abort gebruikt, laat Git me een lijst met gebruik/opties zien.

Dus mijn vorige en huidige filiaalstatus met deze oplossing is:

matbhz@myPc /my/project/environment (branch-123|REBASE-i)
$ git rebase --abort
matbhz@myPc /my/project/environment (branch-123)
$

Antwoord 11

Als je succesvol rebaset op remote branch en niet git rebase --abort kun je nog steeds wat trucjes doen om je werk op te slaan en heb je geen geforceerde pushs.
Stel dat uw huidige branch die per ongeluk opnieuw is gebaseerd, your-branch wordt genoemd en origin/your-branch

bijhoudt

  • git branch -m your-branch-rebased # hernoem huidige branch
  • git checkout origin/your-branch # checkout naar de laatste staat waarvan de herkomst bekend is
  • git checkout -b your-branch
  • controleer git log your-branch-rebased, vergelijk met git log your-branch en definieer commits die ontbreken in your-branch
  • git cherry-pick COMMIT_HASH voor elke commit in your-branch-rebased
  • druk uw wijzigingen door. Houd er rekening mee dat er twee lokale vestigingen zijn gekoppeld aan remote/your-branch en dat u alleen your-branch
  • moet pushen


Antwoord 12

Als u geen harde reset wilt uitvoeren

Je kunt de commit uit de reflog uitchecken, en dan opslaan als een nieuwe branch:

git reflog

Zoek de commit net voordat je begon met rebasen. Mogelijk moet u verder naar beneden scrollen om het te vinden (druk op Enter of PageDown). Noteer het HEAD-nummer en vervang 57:

git checkout HEAD@{57}

Bekijk de branch/commits, en als het correct is, maak dan een nieuwe branch aan met deze HEAD:

git checkout -b new_branch_name

Antwoord 13

Stel dat ik de master rebase naar mijn feature branch en ik krijg 30 nieuwe commits die iets breken. Ik heb gemerkt dat het vaak het gemakkelijkst is om de slechte commits gewoon te verwijderen.

git rebase -i HEAD~31

Interactieve rebase voor de laatste 31 commits (het kan geen kwaad als je er veel te veel kiest).

Neem gewoon de commits die je wilt verwijderen en markeer ze met “d” in plaats van “pick”. Nu worden de commits verwijderd, waardoor de rebase effectief ongedaan wordt gemaakt (als je alleen de commits verwijdert die je net hebt gekregen bij het rebasen).


Antwoord 14

Als je in een filiaal zit, kun je het volgende gebruiken:

git reset --hard @{1}

Er is niet alleen een referentielog voor HEAD (verkregen door git reflog), er zijn ook reflogs voor elke tak (verkregen door git reflog <branch>) . Dus, als je op master zit, dan zal git reflog master alle wijzigingen in die branch weergeven. U kunt naar die wijzigingen verwijzen door master@{1}, master@{2}, enz.

git rebase verandert meestal HEAD meerdere keren, maar de huidige branch wordt slechts één keer bijgewerkt.

@{1} is gewoon een snelkoppeling voor de huidige branch, dus het is gelijk aan master@{1} als je op master zit.

git reset --hard ORIG_HEAD werkt niet als je git reset hebt gebruikt tijdens een interactieve rebase.


Antwoord 15

Het irriteert me mateloos dat geen van deze antwoorden volledig automatisch is, ondanks het feit dat het geautomatiseerd zou moeten zijn (althans meestal). Ik heb een reeks aliassen gemaakt om dit te verhelpen:

# Useful commands
#################
# Undo the last rebase
undo-rebase = "! f() { : git reset ; PREV_COMMIT=`git x-rev-before-rebase` && git reset --merge \"$PREV_COMMIT\" \"$@\";}; f"
# See what changed since the last rebase
rdiff = "!f() { : git diff ; git diff `git x-rev-before-rebase` "$@";}; f"
# Helpers
########
# Get the revision before the last rebase started
x-rev-before-rebase = !git reflog --skip=1 -1 \"`git x-start-of-rebase`\" --format=\"%gD\"
# Get the revision that started the rebase
x-start-of-rebase = reflog --grep-reflog '^rebase (start)' -1 --format="%gD"

Je zou dit moeten kunnen aanpassen zodat je vrij gemakkelijk een willekeurig aantal rebases terug kunt gaan (jongleren met de argumenten is het lastigste deel), wat handig kan zijn als je een aantal rebases snel achter elkaar doet en er iets mee verprutst de weg.

Voorbehoud

Het zal in de war raken als commit-berichten beginnen met “rebase (start)” (doe dit alstublieft niet). Je zou de regex veerkrachtiger kunnen maken om de situatie te verbeteren door iets als dit aan je regex te koppelen:

--grep-reflog "^rebase (start): checkout " 

WAARSCHUWING: niet getest (regex moet mogelijk worden aangepast)

De reden dat ik dit niet heb gedaan, is omdat ik er niet 100% van overtuigd ben dat een rebase altijd begint met afrekenen. Kan iemand dit bevestigen?

[Als je nieuwsgierig bent naar de null (:) commando’s aan het begin van de functie, is dat een manier om bash-aanvullingen voor de aliassen in te stellen]


Antwoord 16

Een andere manier die geen harde reset vereist is om een ​​nieuwe branch te maken met het door jou gewenste startpunt.

Net als bij de andere oplossingen, gebruik je de reflog om het juiste startpunt te vinden.

git reflog

(je kunt hier ook git log -g gebruiken voor meer details)

Vervolgens noteer je de verwijzing naar de commit SHA (bijvoorbeeld: e86a52b851e).

Eindelijk gebruik je het git branch commando.

git branch recover-branch e86a52b851e

Referentie: https:/ /git-scm.com/book/en/v2/Git-Internals-Maintenance-and-Data-Recovery#_data_recovery


Antwoord 17

Wat ik meestal doe is
git reset #commit_hash

naar de laatste commit waarvan ik denk dat rebase geen effect had.

vervolgens git pull

Je branch moet nu precies hetzelfde zijn als master en rebased commits zouden er niet in moeten zitten.

Je kunt nu de commits op deze branch uitkiezen.


Antwoord 18

Ik heb alle suggesties geprobeerd met reset en reflog zonder enig succes. Het herstellen van de lokale geschiedenis van IntelliJ loste het probleem van verloren bestanden op


Antwoord 19

Als je iets verprutst binnen een git-rebase, b.v. git rebase --abort, terwijl je niet-toegewezen bestanden hebt, zullen ze verloren gaan en git reflog zal niet helpen. Dit is mij overkomen en je zult hier buiten de kaders moeten denken. Als je net als ik geluk hebt en IntelliJ Webstorm gebruikt, kun je right-click->local history en teruggaan naar een eerdere staat van je bestand/mappen, ongeacht welke fouten je hebt gemaakt met versiesoftware . Het is altijd goed om nog een failsafe te draaien.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

nineteen + 13 =

Other episodes