Git - Merge with strategy recursive failed

Von in linux

Immer wenn Git Mel­dun­gen wie zum Bei­spiel “Can­not mer­ge” lie­fert, bleibt mir kurz das Herz ste­hen. Der kri­ti­sche User ver­mu­tet ja sofort, dass etwas inmit­ten eines Arbeits­schritts schief gegan­gen ist und malt sich schon aus, wie die Zei­chen im Code kopf­ste­hen. Ich möch­te hier erklä­ren, was die Haupt­ur­sa­chen für das Fehl­schla­gen unter­schied­li­cher Merge-​Vorgänge sind, wie man sie besei­ti­gen kann und war­um gera­de bei Git kei­ne Panik von­nö­ten ist.

Übli­cher­wei­se ver­men­gen zwei Befeh­le unter­schied­li­chen Code mit­ein­an­der: Mit pull holt man sich frem­den Code in sein Pro­jekt, der von Git auch gleich fusio­niert wird, und mer­ge ver­mengt Code aus zwei Bran­ches. In der Regel benö­tigt man auch kei­ne ande­ren Werk­zeu­ge, um Ände­run­gen im Pro­jekt zu ver­brei­ten oder zu inte­grie­ren. Bei­de Befeh­le haben eines gemein­sam: Schla­gen sie fehl, bleibt der Code unver­än­dert. Das ist natür­lich eine wesent­li­che Infor­ma­ti­on. Also, ruhig Blut, auch wenn Git ein­mal kryp­ti­sche Feh­ler­mel­dun­gen wirft.

Es gibt drei Haupt­ur­sa­chen, war­um das Fusio­nie­ren von zwei Code-​Texten fehl­schlägt. Zum Bei­spiel könn­ten Ände­run­gen so nahe bei­ein­an­der lie­gen, sodass Git die Text­zei­len nicht mit­ein­an­der ver­men­gen kann. Eigent­lich ist die­ser Fall gar nicht The­ma die­ses Arti­kels, denn Git mer­ged die­se Ände­run­gen sehr wohl, mar­kiert aber die betrof­fe­nen Stel­len und weist den Benut­zer dar­auf hin, dass er manu­ell nach­bes­sern muss. Die bei­den ande­ren Ursa­chen sind: Ein ver­schmutz­ter Working-​Tree, also Ände­run­gen im Code, die noch nicht dem Index von Git über­ge­ben wur­den (“add”), oder ein ver­schmutz­ter Index, dem­nach Ände­run­gen, die zwar im Index ste­hen, aber noch nicht in den “HEAD” über­nom­men wur­den (“com­mit”). Bei­de Zustän­de machen es Git unmög­lich, eine zusätz­li­che Ände­rung von außen zu fusio­nie­ren, Git kon­tert mes­ser­scharf: Ein Mer­ge wür­de loka­le Ände­run­gen löschen.

Lei­der, und das ist auch der Grund, war­um ich die­sen Arti­kel ver­fasst habe, ist die Ursa­che für obi­ges Pro­blem nicht immer offen­sicht­lich. Übli­cher­wei­se weiß man über durch­ge­führ­te Ände­run­gen Bescheid. Schließ­lich resul­tiert dar­aus der Wunsch, Ände­run­gen in das Repo­si­to­ry zu über­tra­gen. Grund­los wird man wohl kein Mer­ging ansto­ßen, bes­ten­falls hat man nach einem add oder com­mit auf den push ver­ges­sen. Beim Auf­tre­ten von Pro­ble­men in Datei­en, die man ver­meint­lich aber gar nicht ange­rührt hat, kommt dann doch Grü­beln auf. Hier hat man oft äußer­li­che Ände­run­gen an den Datei­en vor­ge­nom­men, wie zum Bei­spiel die Rech­te geän­dert. Oder, etwas was man oft über­sieht, mög­li­cher­wei­se wur­den ander­wei­tig Ände­run­gen her­vor­ge­ru­fen, zum Bei­spiel auto­ma­ti­siert durch Skrip­te. Was der Benut­zer viel­leicht über­sieht, ent­geht Git aber nicht. Wer öfters mit Datei­rech­ten han­tie­ren muss und nicht möch­te, dass Git die Ände­rung mit­be­kommmt, kann dies in der Kon­fi­gu­ra­ti­on ein­stel­len. Eine brauch­ba­re Beschrei­bung dar­über fin­det sich auf stackoverflow.com. Wer Git aber auch zum Nach­voll­zie­hen von Ände­run­gen ein­setzt, ver­zich­tet damit auf ein wert­vol­les Fea­ture. Einen wei­te­ren Grund, war­um ein Mer­ging fehl­schla­gen kann, erklä­re ich im Arti­kel Git fai­led to push some refs: In Bran­ches, in die gemer­ged wur­de, kann erst gepusht wer­den, wenn die Ände­run­gen in das loka­le Pro­jekt über­tra­gen wur­den.

Soviel zu den Ursa­chen, die Lösung ist ein­fach. Im Prin­zip han­delt es sich also meist um einen Work In Pro­gress, und die­ser muss bei­sei­te gescho­ben wer­den, um einen erfolg­rei­chen Mer­ge zu ermög­li­chen. Hier­zu gibt es wie­der zwei Mög­lich­kei­ten. Ers­tens, man über­gibt die geta­ne Arbeit dem Index, also man com­mi­tet und pusht den Code. Das wäre der logi­sche, aber nicht prak­ti­ka­ble Weg. Denn der Ursa­che für das vor­lie­gen­de Pro­blem liegt zugrun­de, dass man mit­ten in einer Arbeit ist. Und in die­sem Zustand will man sei­nen Code in der Regel nicht dem Repo­si­to­ry über­ge­ben. Dar­um, zwei­tens, wird man eher sei­ne unvoll­ende­te Arbeit wie bereits vor­weg­ge­nom­men, bei­sei­te schie­ben, auf einen Sta­pel legen: Man stas­hed den Code, um ihn spä­ter wie­der zu pop­pen. Die­ser in Git höchst prak­ti­ka­ble Vor­gang wur­de von mir bereits aus­führ­lich im Arti­kel “Mit Git Ände­run­gen ver­ste­cken” beschrie­ben. Dabei wird Code qua­si aus dem Working Tree gelöscht, steht aber für spä­te­re Wie­der­her­stel­lung jeder­zeit abruf­bar bereit. Wird die­ser für einen Mer­ge stö­ren­de Code also “ent­fernt”, geht auch das Fusio­nie­ren ohne Feh­ler­mel­dun­gen von­stat­ten und Git beschwert sich folg­lich nicht mehr mit “Mer­ge with stra­te­gy recur­si­ve fai­led”.

Share on Google+Share on RedditTweet about this on TwitterShare on LinkedInShare on FacebookShare on XingEmail this to someone