Is er een manier om door verschillende commits van een bestand te gaan. Stel dat ik een bestand 5 keer gewijzigd heb en ik wil terug naar wijziging 2, nadat ik al gecommit en gepushed heb naar een repository.
In mijn begrip is de enige manier om veel branches te behouden, heb ik dat goed? Als ik het goed heb, heb ik in een paar dagen honderden takken, dus ik begrijp het waarschijnlijk niet helemaal.
Kan iemand dat alsjeblieft ophelderen?
Laten we's beginnen met een kwalitatieve beschrijving van wat we willen doen (veel hiervan wordt gezegd in Ben Straub's antwoord). We'hebben een aantal commits gemaakt, waarvan er vijf een gegeven bestand veranderd hebben, en we willen het bestand terugzetten naar één van de vorige versies. Ten eerste, git houdt geen versienummers bij voor individuele bestanden. Het houdt alleen de inhoud bij - een commit is in essentie een momentopname van de werkstructuur, samen met wat metadata (b.v. commit boodschap). Dus, we moeten weten welke commit de versie heeft van het bestand dat we willen hebben. Zodra we dat weten, moeten we een nieuwe commit doen die het bestand terugzet naar die staat. (We kunnen niet zomaar met de geschiedenis rommelen, omdat we deze inhoud al gepushed hebben, en de geschiedenis bewerken knoeit met alle anderen).
Dus laten we beginnen met het vinden van de juiste commit. Je kunt heel gemakkelijk de commits zien die wijzigingen in een gegeven bestand(en) hebben aangebracht:
git log path/to/file
Als je commit boodschappen niet goed genoeg zijn, en je moet zien wat er in elke commit aan het bestand gedaan is, gebruik dan de -p/--patch
optie:
git log -p path/to/file
Of, als je de grafische weergave van gitk prefereert
gitk path/to/file
Je kunt dit ook doen als je gitk gestart hebt via het view menu; een van de opties voor een view is een lijst van paden om op te nemen.
Hoe dan ook, je'zult in staat zijn om de SHA1 (hash) te vinden van de commit met de versie van het bestand dat je wilt. Nu hoef je alleen nog maar dit te doen:
# get the version of the file from the given commit
git checkout <commit> path/to/file
# and commit this modification
git commit
(Het checkout commando leest eerst het bestand in de index, en kopieert het dan naar de werk boom, dus het is niet nodig om git add
te gebruiken om het aan de index toe te voegen als voorbereiding op het committen).
Als je bestand geen eenvoudige geschiedenis heeft (b.v. hernoemingen en kopieën), zie VonC's uitstekende opmerking. git
kan worden aangestuurd om zorgvuldiger naar zulke dingen te zoeken, ten koste van de snelheid. Als je er zeker van bent dat de geschiedenis eenvoudig is, hoef je je niet druk te maken.
Git'denkt niet in termen van bestandsversies. Een versie in Git is een momentopname van de hele boom.
Gegeven dit, wat je echt wilt is een boom die de laatste inhoud van de meeste bestanden heeft, maar met de inhoud van één bestand hetzelfde als het 5 commits geleden was. Dit zal de vorm aannemen van een nieuwe commit bovenop de oude, en de laatste versie van de boom zal hebben wat je wilt.
Ik weet niet of er een one-liner is die een enkel bestand terugzet naar de inhoud van 5 commits geleden, maar de lo-fi oplossing zou moeten werken: checkout master~5
, kopieer het bestand ergens anders naar toe, checkout master
, kopieer het bestand terug, commit dan.
Je kunt een diff nemen die de veranderingen ongedaan maakt die je wilt en die vastleggen.
Bijvoorbeeld, als je de veranderingen in het bereik van..tot
ongedaan wilt maken, doe dan het volgende
git diff to..from > foo.diff # get a reverse diff
patch < foo.diff
git commit -a -m "Undid changes from..to".