Github frustriert mich gerade stark, seit Tagen komme ich damit nicht weiter und schlage mich damit rum anstatt mich mit dem Code an sich beschäftigen zu können. Was mache ich falsch? Okay, ganz von Anfang, mehrere Probleme. Ich habe ein Repository mit einem Branch dem ich zuarbeiten möchte. Da ich auf das Repository keinen direkten Zugriff habe erstelle ich einen Fork in meinen Account. Das erste was ich gemacht habe ist den Branch zu clonen, zu bearbeiten und schliesslich einen Pull-Request zu stellen. Soweit alles gut. Nun hat der Autor aber den Branch selber verändert, ohne das er meinen Pull-Request vorher bearbeitet hätte. Wie bekomme ich meinen Fork auf den aktuellen Stand? Nach einigen Stunden habe ich schlieslich meinen Fork gelöscht und einen neuen Fork erstellt. Aber das kann ja wohl kaum die Lösung sein? In dem neuen Fork habe ich diesmal einen neuen Branch erstellt, weil ich grundsätzlich auch Dateien bearbeiten muss die ich nicht per Pull-Request in das Projekt zurück spielen will, lokale Änderungen die nur für mich relevant sind. Wie bekomme ich jetzt gezielt einzelne Dateien von einem Branch in den anderen um letztlich gegen das Original-Repository einen Pull-Request stellen zu können? Nachdem ich da mit der Github Webseite und TortoiseGit nicht weiter gekommen bin habe ich die "GitHub Desktop" angeworfen und "Merge into current branch" ausprobiert. Mit dem Ergebnis das ohne jedes Feedback oder Rückfragen alle Dateien in dem Ziel-Branch überschrieben wurden, obwohl ich nur eine Datei ändern wollte. Damit bin ich gerade an dem Punkt das ich im Grunde genommen nur wieder den Fork löschen und von vorne anfangen kann. Kann ich wirklich nur von Hand die gewünschten Dateien in den Branch kopieren?
Du solltest dich erstmal mit den Grundkonzepten von git (!= github) vertraut machen, bevor du zwanzig Tools darauf wirfst die irgendwelche Dinge tun die du dann nicht nachvollziehen kannst. Generell, wenn es Upstream (="von anderen Leuten") Änderungen gibt, die du in deinen eigenen Branch übernehmen möchtest, "git pull" oder "git pull --rebase". Einzelne Dateien von einem Branch in einen anderen zu kopieren geht mit einer bestimmten Syntax von "git checkout", aber das ist auch nicht die Operation die du machen willst, oder? Du willst z.B. einen einzelnen Commit importieren; das geht mit "git cherry-pick".
Du wirst dich wohl oder übel mit den Grundlegenden Operationen von git beschäftigen müssen: merge, rebase und commit Wie man das genau mit deinem jeweiligen GUI umsetzt kann ich dir nicht sagen, aber unter https://git-scm.com/book/en/v2/Getting-Started-Git-Basics findest du einen Einstieg.
1. Fork Upstream Sync: https://help.github.com/articles/syncing-a-fork/ 2. Git Branching, Rebasing: https://git-scm.com/book/de/v1/Git-Branching-Rebasing 3. Pull Requests nach Möglichkeit immer in einem eigenen Branch erstellen der dann vom Maintainer gemerged werden kann. Manchmal ist es allerdings einfacher seinen Fork zu syncen und danach die Dateien manuell zu kopieren...kommt auf das Projekt drauf an
Nachdem ich inzwischen fünf Mal oder so den Fork gelöscht und neu erstellt habe ist das ja auf dem gleichen Stand für den Moment. Mit einem abweichenden Stand habe ich git nicht dazu bringen können den Branch aus dem übergeordneten Repository mit den neuen Daten zu überschreiben. Wie auch immer, das kann ich gerade nicht neu ausprobieren. Bleibt im Moment das andere Problem, wie bekomme ich mit Git einzelne Dateien von einem Branch in den anderen? TestX schrieb: > 3. Pull Requests nach Möglichkeit immer in einem eigenen Branch > erstellen der dann vom Maintainer gemerged werden kann. Okay, geht natürlich auch, bringt aber die gleichen Probleme mit sich. Dafür muss ich also einen neuen Branch von dem ableiten zu dem ich einen Pull-Request erstellen will - easy. Und dann aus meinem Arbeits-Branch das in den Branch überführen was ich per Pull-Request ins Projekt bringen will. Wie macht man das geschickt? Auf Github selber gibt es kein Cherry-Picking, das fällt also aus, alles oder nichts, was anderes geht nicht. Und für "git cherry-pick" muss ich wohl vorher selber wissen und dann da festelegen was ich haben will. Wobei mich der Hilfstext von "git cherry-pick" gerade überhaupt nicht vorwärts bringt, keine Ahnung wie man da von einem Branch in einen anderen kommen soll. Ich vermute gerade eher, das geht damit gar nicht, ich will ja keinen Commit kopieren, sondern bestimmte Dateien die vielleicht oder auch nicht Teil von dem einen oder anderen Commit waren. Dann kann ich aber auch gleich die Dateien von Hand kopieren und per Commit/Push in den Branch schieben.
Hä? Dateien die Teil eines Commits sind? Wovon sprichst du? Ich denke, das ist ein typischer Fall von "XY-Problem". https://en.wikipedia.org/wiki/XY_problem
Rudolph R. schrieb: > Bleibt im Moment das andere Problem, wie bekomme ich mit Git einzelne > Dateien von einem Branch in den anderen? Git ist nicht dateibasiert. Git ist commit- (changeset-) basiert. Wenn du z.B. 'master' hast, dann einen 'branch' machst und auf 'master' weiter commits machst, kannst du diese entweder mit git-pull alle in 'branch' reinziehen, oder mit git-cherry-pick einzelne commits reinziehen. Wenn du "einzelne Dateien" reinziehen willst, musst du das entweder manuell eben so machen und einen neuen commit erstellen, oder ein commit pro Datei erstellen und den dann mit cherry-pick übernehmen.
Gituser schrieb: > Rudolph R. schrieb: >> Bleibt im Moment das andere Problem, wie bekomme ich mit Git einzelne >> Dateien von einem Branch in den anderen? > > Git ist nicht dateibasiert. Git ist commit- (changeset-) basiert. Naja wenn du dir anschaust wie es intern funktioniert ist eigentlich genau das Gegenteil der Fall, aber es verhält sich nach außen eher so, ja.
Sven B. schrieb: > Naja wenn du dir anschaust wie es intern funktioniert ist eigentlich > genau das Gegenteil der Fall, Was meinst du damit? Nur weil die .git Datenbank in Dateien gespeichert wird, ist git nicht dateibasiert. Es ist ein gewolltes Designmerkmal von git, dass commits dateiübergreifend sind.
Gituser schrieb: > Git ist nicht dateibasiert. Git ist commit- (changeset-) basiert. Na bitte, dann habe ich das mit dem Cherry-Pick und Commits doch nicht so falsch verstanden in meinem letzten Kommentar. Mein Fehler war jetzt, das ich inital zu viele Änderungen auf einmal gemacht und in einen Commit gepackt habe, das wird dann nichts. Da muss man auch erstmal drauf kommen, dass eine Revisions-Verwaltung nicht Datei-basiert ist. Also kleinere Schritte, verschiedene Änderungen getrennt Einchecken. Danke!
Gituser schrieb: > Sven B. schrieb: >> Naja wenn du dir anschaust wie es intern funktioniert ist eigentlich >> genau das Gegenteil der Fall, > > Was meinst du damit? > Nur weil die .git Datenbank in Dateien gespeichert wird, ist git nicht > dateibasiert. > Es ist ein gewolltes Designmerkmal von git, dass commits > dateiübergreifend sind. Ein "commit" in git ist aber kein Patch oder Diff zu irgendeinem anderen Zustand, sondern im Gegenteil ein Archiv mit dem kompletten Verzeichnisbaum in einem bestimmten Zustand zusammen mit ein paar Metainformationen. Die mehr oder wenige einzige Relation zu anderen Zuständen entsteht dadurch, dass zu den Metainformationen ein "parent"-Commit dazugehört. Die Diffs werden dann nur auf Anfrage berechnet, ein Diff ist kein Objekt in git, was irgendwo abgespeichert wird oder für die Funktionsweise des Tools irgendwie elementar wäre. Außer für ein paar spezielle Operationen (rebase, diff, cherry-pick etc) kommen Diffs eigentlich gar nicht vor. Die Aussage "git ist changeset-basiert" ist aus diesem Blickpunkt deshalb ziemlich irreführend.
https://xkcd.com/1597/ Hol Dir eines der unzähligen GIT Cheat Sheet im Netz. Dann beschäftige Dich mit GIT. Wenn man es mal begriffen hat, ist es trivial und man weiss die Vorteile zu schätzen. Grüsse, René
Sven B. schrieb: > Die Aussage "git ist changeset-basiert" ist aus diesem Blickpunkt > deshalb ziemlich irreführend. Nö. Es ist auch aus diesem Blickwinkel ziemlich richtig. Du sagst doch selbst, dass ein commit ein snapshot des gesamten Repositories und nicht einzelner Dateien ist.
René H. schrieb: > https://xkcd.com/1597/ http://ohshitgit.com/ Alternativ: https://de.udacity.com/course/version-control-with-git--ud123 https://de.udacity.com/course/github-collaboration--ud456
Christopher J. schrieb: > René H. schrieb: >> https://xkcd.com/1597/ > > http://ohshitgit.com/ Den kannte ich noch nicht, thx :-D Grüsse, René
Gituser schrieb: > Sven B. schrieb: >> Die Aussage "git ist changeset-basiert" ist aus diesem Blickpunkt >> deshalb ziemlich irreführend. > > Nö. Es ist auch aus diesem Blickwinkel ziemlich richtig. Du sagst doch > selbst, dass ein commit ein snapshot des gesamten Repositories und nicht > einzelner Dateien ist. Ein Changeset ist aber kein Set von Dateien, sondern ein Set von Änderungen. Sagt schon der Name.
Sven B. schrieb: > Ein Changeset ist aber kein Set von Dateien, sondern ein Set von > Änderungen. Sagt schon der Name. Habe ich etwas anderes behauptet? Genau das ist doch der Punkt. Git verwaltet keine Dateiversionen, sondern nur Änderungen im Branch als eine Einheit: Das Changeset.
Das ist ein Ding! ;-O Vater hat mir gerade das Buch Rene Preißel / Bjorn Stachmann Dezentrale Versionsverwaltung im Team Grundlagen und Workflows ISBN 978-3-86490-130-0 in die Hängematte geworfen, vielleicht interessiert es einen, das Teil ist in Deutsch. mfg
Okay, I habe einen Commit-Branch erstellt, die Änderungen gegenüber dem Original Branch im Original Repository da drin gemacht, committet, gepusht, einen Pull-Request erstellt und der Maintainer hat meinen Pull-Request akzeptiert und gemerged. Soweit alles schick. Damit war mein Branch in meinem Fork allerdings um die entsprechenden Commits zurück. Das hier: https://help.github.com/articles/syncing-a-fork/ Hilft bei dem Problem überhaupt nicht. "git fetch upstream" gab nur die Fehlermeldung das es keinen Branch "upstream" gibt. Also mindestens ist das unvollständig. Ich bin dann hier nach vorgegangen: https://webapps.stackexchange.com/questions/28998/how-do-you-update-a-github-repo-fork-in-the-web-interface/58140#58140 Also ich habe einen Pull-Request von dem anderen Repository auf mein eigenes erstellt und verarbeitet. Jetzt ist das wieder im Grunde auf dem gleichen Stand, allerdings meldet Github nun, das der Branch in meinem Repository einen Commit Ahead wäre. Dann habe ich zusätzlich mal das hier probiert: https://superuser.com/questions/456145/how-can-i-resync-a-fork-from-original git remote add upstream https://github.com/upstream-username/projectname.git git pull upstream master git push Nachdem ich denn herausgefunden hatte wie ich aus VIM raus komme für die commit-message (:wq ENTER ...) hat das auch funktioniert soweit. Nur ist mein Fork jetzt 2 commits ahead... Meine Fresse, ich möchte doch nur, dass der Branch im meinem Fork auf dem gleichen Stand ist wie der entsprechende Branch im Original-Repository. Keinen Commit ahead oder zurück, 1:1 der Stand. Und der einzige Weg bisher das zu erreichen war den Fork zu löschen und neu zu erstellen -> das kann es ja wohl nicht sein. Soweit ist Git oder eher Github eigentlich nur zum kotzen beim Arbeiten mit zwei Repositories.
Gituser schrieb: > Sven B. schrieb: >> Ein Changeset ist aber kein Set von Dateien, sondern ein Set von >> Änderungen. Sagt schon der Name. > > Habe ich etwas anderes behauptet? > Genau das ist doch der Punkt. Git verwaltet keine Dateiversionen, > sondern nur Änderungen im Branch als eine Einheit: Das Changeset. Und das genau ist falsch. Git verwaltet Versionen von Dateien, keine Changesets. Ein "commit" in git ist eine Liste von Objekten, und jede Version jeder Datei ist ein Objekt. Wenn du eine Datei änderst und einen neuen Commit mit dieser Änderung erstellst, legt git ein neues Objekt an für die neue Datei, in der es einfach den Inhalt der neuen Datei komprimiert (völlig unabhängig vom alten Zustand), und dann einen Commit, der einfach nur eine Liste von Objekten (=Datei in einem bestimmten Zustand) ist. In die Metadaten des Commits wird der Name des vorherigen Commits notiert. Mit Diff oder Changeset hat das gar nichts zu tun. Das Diff wird dann wenn du danach fragst anhand der Angabe des vorherigen Commits berechnet. Schau dir zum Beispiel mal "git ls-tree HEAD" an, da bekommst du eine Liste mit Objects im HEAD des Repos, und daneben steht immer ein sha1-Hash. Diese Liste ist im Wesentlichen ein Commit. Die Dateien in den Versionen, die dort aufgelistet sind, sind in .git/objects/ab/cdefgh... wobei ab die ersten 2 Buchstaben des sha1-Hashs sind. Deshalb ändert sich auch zwangsläufig der sha1-Hash eines Commits, wenn man irgendwo in der Historie etwas ändert: weil der Hash nicht das Changeset identifiziert, was durch diesen Commit eingeführt wird (das gibt's nämlich nicht), sondern den Zustand des Repositories bei diesem Commit.
Sven B. schrieb: > Gituser schrieb: >> Sven B. schrieb: >>> Ein Changeset ist aber kein Set von Dateien, sondern ein Set von >>> Änderungen. Sagt schon der Name. >> >> Habe ich etwas anderes behauptet? >> Genau das ist doch der Punkt. Git verwaltet keine Dateiversionen, >> sondern nur Änderungen im Branch als eine Einheit: Das Changeset. > > Und das genau ist falsch. Git verwaltet Versionen von Dateien, keine > Changesets. Alles nicht komplett falsch, aber auch nicht komplett richtig. Git verwaltet eben weder Dateiversionen noch Changesets. Git verwaltet commits. Ein commit besteht aus einem Kommtar und einem Snapshot; ein Snapshot wie ein Image einer Festplatte. Nur dass kein Image einer Festplatte gemacht wird, sondern eben ein "Image", aka Snapshot, eines kompletten Verzeichnisbaums. Wie bei einem Festplatten-Image-Tool kann man auch einzelne Dateien aus dem commit (Snapshot) extrahieren, wenn man möchte. Oder man kann sich die Unterschiede von commits anschauen. Wie Git intern die commits verwaltet, ob es gleiche Dateien nur einmal speichert oder nicht, ob es Diffs speichert oder nicht, spielt keine Rolle. Der Punkt ist: Ein Commit ist ein Snapshot eines Verzeichnisbaums mit einer Commit-Nachricht und noch ein paar anderen Metadaten.
Sven B. schrieb: > Und das genau ist falsch. Git verwaltet Versionen von Dateien, keine > Changesets. > > Ein "commit" in git ist eine Liste von Objekten, ... Was git intern in seiner Datenbank macht - weiß ich sehr wohl - interessiert hier nicht. Wir arbeiten hier mit dem offiziellen git user-Interface. Und dort gibt es keine Versionen von Dateien. Ende der Diskussion. Wenn du das willst, gehe zurück zu CVS.
Rudolph R. schrieb: > "git fetch upstream" gab nur die Fehlermeldung das es keinen Branch > "upstream" gibt. > Also mindestens ist das unvollständig. Lies einfach mal ein Grundlagenbuch https://git-scm.com/book/en/v2 Es bringt nichts, wenn wir dir hier den Befehl nennen. Du kennst die Grundlagen von git offensichtlich nicht. Und die sind nicht so schwer. Also lies die ersten paar Abschnitte des Buchs.
Gituser schrieb: > Es bringt nichts, wenn wir dir hier den Befehl nennen. Du kennst die > Grundlagen von git offensichtlich nicht. Dafür komme ich aber schon gut klar. Innerhalb eines Repositories habe ich ja erstmal kein Problem mehr. > Und die sind nicht so schwer. Also lies die ersten paar Abschnitte des > Buchs. Und die ersten paar Abschnitte bringen mich jetzt wie weiter bei der Arbeit mit zwei verschiedenen Repositories? Oder welcher der Kommentare dazu hier bisher? Was nützt mir ein Re-Sync mit dem Upstream Repository wenn hinterher mein Branch einen Commit weiter ist als das Original, obwohl das inhaltlich dann auf dem gleichen Stand ist? So wie es sich bisher darstellt werde ich wohl regelmäßig den Fork löschen und neu erstellen müssen. Das ist deutlich weniger Aufwand und im Ergebnis sauberer. Nachdem der Pull-Request aus meinem Fork durch ist brauche ich das Repository ja auch nicht mehr.
Gituser schrieb: > Sven B. schrieb: >> Und das genau ist falsch. Git verwaltet Versionen von Dateien, keine >> Changesets. >> >> Ein "commit" in git ist eine Liste von Objekten, ... > > Was git intern in seiner Datenbank macht > - weiß ich sehr wohl > - interessiert hier nicht. Wir arbeiten hier mit dem offiziellen git > user-Interface. Und dort gibt es keine Versionen von Dateien. Ende der > Diskussion. Wenn du das willst, gehe zurück zu CVS. Naja, das gesamte Verhalten macht halt keinen Sinn, wenn du das so betrachtest, aber bitteschön. Warum gibt es zum Beispiel einen Merge-Commit wenn ich Commits von einem Remote pulle, aber schon selbst einen Commit gemacht habe, nicht aber, wenn es in der umgekehrten Reihenfolge passiert? Das ist mit deiner Darstellung nicht schlüssig erklärbar, und ist bei Versionskontrollsystemen wie svn (die tatsächlich mit Deltas arbeiten) auch nicht der Fall.
Rudolph schrieb: > Dafür komme ich aber schon gut klar. > Innerhalb eines Repositories habe ich ja erstmal kein Problem mehr. Genau deshalb solltest du die Grundlagen lesen. Es spielt nämlich kaum eine Rolle, wo die Repositories liegen und wie viele es sind. Die entsprechenden Kapitel sind "2. Git Basics" und insbesondere "3. Git Branching".
Sven B. schrieb: > Naja, das gesamte Verhalten macht halt keinen Sinn, wenn du das so > betrachtest, aber bitteschön. Warum gibt es zum Beispiel einen > Merge-Commit wenn ich Commits von einem Remote pulle, aber schon selbst > einen Commit gemacht habe, nicht aber, wenn es in der umgekehrten > Reihenfolge passiert? Das ist mit deiner Darstellung nicht schlüssig > erklärbar Was du schreibst ergibt überhaupt keinen Sinn. Was haben merge-commits denn bitte mit der angeblichen Dateibasiertheit von git zu tun? git commits sind eine Kette. Wenn diese Kette beim pull/merge verlängert wird, ist es ein fast-forward. Wenn sich die Kette nicht verlängern lässt, ist ein ein merge-commit. Das hat mit einzelnen Dateien überhaupt gar nichts zu tun.
Egal, das führt zu nichts. Du weißt ja offenbar wie es funktioniert und möchtest es trotzdem anders erklären, sind wir halt verschiedener Meinung. Ich hätte es lieber näher an dem erklärt wie git es intern tut, weil das meiner Meinung nach dann leichter nachvollziehbar ist und eher erlaubt zu extrapolieren wie sich das Tool in anderen Situationen verhält.
Mein größtes Problem als ich mit git angefangen habe war zu begreifen, dass git pull, anders als der Befehl aussieht, zwei unterschiedliche Verhalten hat und eigentlich auch intern zwei Befehle hintereinander verknüpft. Zunächst einmal allgemein ein git fetch. Abrufen vom verknüpften Remote. Und dann, was tückisch ist, je nach Zustand bzw. Delta von lokalen und remote Branch, ein git merge oder einen git rebase. Ich für meinen Teil entscheide sowas gerne selbst und verzichte daher auf git pull, wenn ich in einem Repository arbeite, gänzlich. Für ein Rebase nutze ich ein kleines Script* welches den rebase Commit für Commit durchgeht um Konflikte Recht einfach zu beheben. * https://github.com/Traumflug/Teacup_Firmware/blob/master/tools/git-step-rebase
Nico W. schrieb: > Zunächst einmal allgemein ein git fetch. Abrufen vom verknüpften Remote. > Und dann, was tückisch ist, je nach Zustand bzw. Delta von lokalen und > remote Branch, ein git merge oder einen git rebase. Was meinst du mit rebase an der Stelle? Ein fast forward ist kein rebase. > Für ein Rebase nutze ich ein kleines Script* welches den rebase Commit > für Commit durchgeht um Konflikte Recht einfach zu beheben. Warum nicht einfach git rebase --interactive?
Fast-forward ist aber auch kein merge... Das Script geht jeden Commit einzeln durch und macht einen rebase drauf. Wenn man das ganze Packet auf einmal einem Rebase unterzieht, dann bekommst du zum Teil Konflikte die man nicht mehr so einfach überblicken kann. Wenn du also in deinem Master branch bist und einen rebase auf dein Experimental machen möchtest und dieser 2 Commits ahead ist, dann macht das Script: git rebase experimental~1 git rebase experimental Sobald ein Konflikt aufkommt, bricht das Script ab. Den Konflikt muss man dann natürlich lösen. Anschließend ein git rebase --continue. Danach kann man das Script wieder ausführen, bis alle Commits im master sind. Dadurch bekommt man eine schöne lineare History ohne Merge.
Ich sehe jetzt keinen Unterschied zu einem normalen git rebase --interactive. Auch dort kann man stoppen, umsortieren und editieren.
Klar kann man auch per Hand alle Commits bis auf einen einzigen raus löschen um dann Schritt für Schritt alles durchzuarbeiten. Oder man nimmt das Script. Dabei geht es nicht ums umsortieren sondern einem kompletten Rebase auf den eigentlichen Branch um eine lineare History zu bekommen. Wenn ich mit git arbeite möchte ich keinen merge commit. Und wenn dann doch mal 20 oder mehr Commits ahead sind, dann wirst du dir bei einem normalen rebase schnell ins Knie schießen.
Nico W. schrieb: > Klar kann man auch per Hand alle Commits bis auf einen einzigen raus > löschen um dann Schritt für Schritt alles durchzuarbeiten. Hast du --interactive mal probiert? Das ist eben nicht alles per Hand durchgehen. > Wenn ich mit git arbeite möchte ich keinen merge commit. Der entsteht beim rebase ja auch gar nicht.
Nico W. schrieb: > Wenn du also in deinem Master branch bist und einen rebase auf dein > Experimental machen möchtest übrigens halte ich diese Arbeitsweise auch für sehr merkwürdig. Warum machst du kein rebase deines Branches auf master (also umgekehrt)? Danach ist das pull von branch nach master nur ein fast forward. Du hast keine merge commits und vor allem brauchst du auch kein force-push für master auf dein origin (und falls es weitere Clones gibt, machst damit auch diese nicht kaputt. Wenn du einen rebase von master machst, zwingst du deine clones ja auch so einem rebase, statt einem einfachen ff-pull).
Wir reden lediglich ein wenig aneinander vorbei. Wenn ich im Master einen rebase mit dem experimental mache, dann gehen die Commits vom experimental aufs Master drauf. Nicht dazwischen oder sonst wo hin. Und ich habe mir das interaktive rebase angesehen. Nutze ich auch um Commits zusammen zu fassen oder in einem Testbranch zu löschen. Manchmal auch um sie umzusortieren. Hast du dir denn das Script mal angesehen? Speziell wenn der Master durch einen früheren rebase von einem anderen Branch ahead und behind ist?
Nico W. schrieb: > Wir reden lediglich ein wenig aneinander vorbei. > > Wenn ich im Master einen rebase mit dem experimental mache, dann gehen > die Commits vom experimental aufs Master drauf. Nicht dazwischen oder > sonst wo hin. Das befürchte ich allerdings auch. > Hast du dir denn das Script mal angesehen? Ja. > Speziell wenn der Master > durch einen früheren rebase von einem anderen Branch ahead und behind > ist? Gleichzeitig ahead und behind? Was ist das? Kannst du vielleicht mal den Fall, in dem das script nützlich ist, aufzeichnen?
Du machst einen neuen Branch A aus dem master. Nun fügst du dort ein paar Änderungen ein. Jemand anderes arbeitet an einem Branch B. Nun bist du mit A fertig und kannst diesen recht einfach mit dem Master vereinen. Der Andere mit Branch B möchte nun diese Änderungen zunächst einmal in seinen Branch einarbeiten, da er zum Teil im gleichen Bereich Änderungen vollzogen hat. Jetzt kann er jeden einzelnen Commit der zwischen Master und A enstanden ist einzeln einarbeiten.
1 | --- A1 -- A2 -- A3 |
2 | / |
3 | master |
4 | \ |
5 | --- B1 -- B2 |
6 | |
7 | git checkout master |
8 | git rebase A |
9 | |
10 | master - A1 - A2 - A3 |
11 | |
12 | git checkout B |
13 | git-step-rebase master |
14 | |
15 | 1. master - A1 - B1' - B2' |
16 | 2. master - A1 - A2 - B1'' - B2'' |
17 | 3. master - A1 - A2 - A3 - B1''' - B2''' |
Grob wäre das in etwa der Aufbau. Wenn das ganze nur ein oder zwei, meinetwegen auch ein paar mehr, Commits sind, geht das mit einem normalen Rebase meist noch recht Problemlos. Aber wenn es mehr wird, kann es schnell zu Problemen kommen. Ich habe zum Beispiel vor zwei Jahren einen Port erstellt von einer Firmware. Hier war zunächst ein Master mit AVR und LPC Support. Diesen habe ich hergenommen um meinen STM-Port draufzupacken. Nach ca. einem Jahr war ich fertig (War alles Neuland für mich und einfach auch nur ein kleines Hobby) und in der Zeit sind ca. 100 Commits im Master entstanden. Um dort eine lineare History auch mit dem Script zu erstellen ist eine kleine Herausforderung. Ohne fast kaum zu händeln.
Nico W. schrieb: > git checkout master > git rebase A Ok, das habe ich befürchtet. Das ist eine völlig unübliche Nutzung von rebase. Üblicher wäre eher sowas wie git checkout master git pull . A #Das ist ein FF git checkout B git rebase master #eventuell --interactive git checkout master git pull . B #Das ist ein FF
Völlig unüblich? Glaube ich kaum. Nen local pull habe ich bisher noch nie gesehen. Aber ist in dem Bereich auch völlig egal, da das Ergebnis identisch ist. Ich würde bei deinen git pull . A noch ein -ff-only dran setzen.
Nico W. schrieb: > Aber ist in dem Bereich auch völlig egal, da das Ergebnis identisch ist. Na dann sehe ich die Notwendigkeit für das Script immer noch nicht. Ich würde das Script auch alleine deshalb in Frage stellen, weil alle git-Nutzer, außer du, ohne dieses script gut auskommen. Also musst du einen Spezialfall haben. Wenn du keinen Spezialfall hättest, wäre diese Funktionalität schon lange in git drin. > Nen local pull habe ich bisher noch nie gesehen. Lokale pulls waren schon immer ganz normal. In frühen Versionen ging es auch gar nicht anders.
Die meisten Gituser nutzen Rebase selten bis nie, arbeiten eher mit nem Merge bzw. pull-Requests. Ich möchte keinen Merge. Ich möchte eine komplette lineare History. Wenn du einen Arbeits-Branch hast mit 100 commits, der Master 100 commits ahead ist, dann wirst du schnell mit einem normalen rebase Probleme bekommen. Vielleicht hast du selten so einen großen Unterschied zwischen einem Arbeits-Branch und dem eigentlichen Master. Dann mag das kaum einen Unterschied machen. Hinter der Hütte macht das Script in etwa:
1 | git checkout issue-67 |
2 | ---- git-step-rebase ---- |
3 | git rebase experimental^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
4 | git rebase experimental^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
5 | git rebase experimental^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
6 | git rebase experimental^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
7 | git rebase experimental^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
8 | [...] |
9 | git rebase experimental^^ |
10 | git rebase experimental^ |
11 | git rebase experimental |
Wenn du das nicht benötigst ist es ja auch gut. Ich für meinen Teil habe das bei größeren Geschichten immer gerne dabei.
Nico W. schrieb: > Die meisten Gituser nutzen Rebase selten bis nie, arbeiten eher mit nem > Merge bzw. pull-Requests. Ich möchte keinen Merge. Ich möchte eine > komplette lineare History. Falsch. Aber so richtig. Mit rebase sorgst du dafür, das dein Branch problemlos in den Master gemergt werden kann. Das ist oftmals sehr viel eleganter, als von einem völlig weggetrifteten Zweig abertausende Konflikte bei einem direkten Merge zu beheben. Wie die Historie in meinem lokalen Brach aussieht, ist völlig irrelevant. Es ist DEINE Aufgabe, das es nicht zu Konflikten kommt - nicht derjenigen Person, welche den Merge durchführen will. Man sieht leider an vielen Stellen, das Git wie SVN oder jedes beliebig zentrale Versionsmanagement Tool verwendet wird. Davon muss man sich einfach lösen.
Hater schrieb: > Man sieht leider an vielen Stellen, das Git wie SVN oder jedes beliebig > zentrale Versionsmanagement Tool verwendet wird. Davon muss man sich > einfach lösen. Das sehe ich auch so. Ich kenne die beschriebenen Probleme nicht. Wenn man ständig merge-Konflikte hat, dann ist etwas im Entwicklungsmodell falsch. Die Entwickler sprechen sich nicht ab. Oder wenn es nur einen Entwickler gibt, dann zieht er seine Nebenbranches zu spät nach. Wenn ich in master etwas tue, von dem ich weiß, dass es Konflikte in einem Branch verursachen wird, dann mache ich natürlich schnellstmöglich einen rebase des Branches. Und genau das macht ja dieses Script. Nur eben viel später. Also dann, wenn ich gar nicht mehr weiß, wie dieser Konflikt aufzulösen ist. Für mich ist dieses Vorgehen nicht sinnvoll. Für mich gibt es nur zwei Arten von Branches: 1) Tote Branches. Diese werden natürlich auch nicht mehr rebased. 2) Aktive Branches. Diese ziehe ich natürlich regelmäßig per Rebase nach und warte nicht, bis hunderte Konflikte aufgelaufen sind. Ich sehe nur Nachteile darin einen Branch nie zu rebasen und dann am Ende beim Merge/Rebase nach master alle Konflikte aufzulösen.
Rudolph R. schrieb: > git remote add upstream > https://github.com/upstream-username/projectname.git > git pull upstream master > git push > > Nachdem ich denn herausgefunden hatte wie ich aus VIM raus komme für die > commit-message (:wq ENTER ...) hat das auch funktioniert soweit. > Nur ist mein Fork jetzt 2 commits ahead... Wenn alles nach Plan gelaufen wäre, sollte VIM hier gar nicht ins Bild kommen. Und tatsächlich: 2 Commits ahead? Einer davon ist wohl ein Merge-commit (dessetwegen VIM gekommen ist). Dann ist da noch ein weiterer Commit. Das muss einer sein, den du zusätzlich zu denen von "upstream" und deinem Pull Request in deinem Repository gehabt hast. Klingelt da was? BTW, ich verwende gitk, um mir einen Überblick über die Branches zu verschaffen. Versuche mal
1 | gitk --branches --remotes=upstream HEAD |
Kann sein, dass da viel Kram auftaucht, aber man sollte sehen, wo man sich befindet (gelber Knoten) und auf welchen Bahnen sich der/die Branches von "upstream" bewegen. Es könnte auch passiert sein, dass "upstream" deinen Pull Request abgeändert hat. Dann würde man das in gitk relativ leicht erkennen können.
Na, ich habe schon Stuss mit dem Repository gemacht, erst den Merge-Request über die Webseite und dann noch mal den Sync über die Kommando-Zeile. Einfach mal Ausprobieren das ganze schadet ja erstmal nicht. Beim Merge-Request über die Webseite kommt halt heraus, dass die Branches in den Repositories zwar identisch sind, der Branch in meinem Repository aber dennoch einen Commit ahead ist. Und beim Sync über die Kommando-Zeile mit den ohnehin schon identischen Repositories wurde ein Commit generiert den ich zu kommentieren automatisch aufgefordert wurde. Der zweite Commit sollte eigentlich leer sein, ist es aber gar nicht. Und wohl gemerkt, den Branch habe ich selber gar nicht in dem Sinne angefasst als das ich da drin irgendwelche Dateien manipuliert hätte. Inzwischen ist der Branch den ich dann bearbeiten will gegenüber meinem Repository um 5 Commits zurück und ich habe immer noch keine Antwort auf die Frage wie ich das Synchronisiert bekomme. Ausser jetzt mein Repository zu löschen und neu zu erstellen. Ich will nur, dass auf Github steht: "This branch is even with ..." Und das nehme ich dann als Arbeitsgrundlage, zweige einen Branch ab zum Rumspielen und einen weiteren in den ich die für einen Pull-Request relevanten Änderungen einspielen kann. Und wenn dann da steht "This branch is x commits behind...", dann möchte ich das schlicht nur so re-synchroniseren, dass da wieder steht "This branch is even with..." und nicht etwa "This branch is 1 commit ahead...". Statt dessen wird hier nur sinnlos am Thema vorbei diskutiert. Eine Anwort auf die Fragestellung könnte auch sein, dass das so gar nicht funktioniert mit Git. Okay, wenn das so ist werde ich wohl nicht drum herum kommen mein Repository immer wieder zu löschen und einen frischen Fork zu erstellen. Aber irgendwie klingt das schon reichlich beknackt.
Rudolph R. schrieb: > Inzwischen ist der Branch den ich dann bearbeiten will gegenüber meinem > Repository um 5 Commits zurück und ich habe immer noch keine Antwort auf > die Frage wie ich das Synchronisiert bekomme. git fetch origin git rebase origin/master Wenn dein remote origin und der branch master heißen.
Wieso Origin? Es geht doch darum das Repository mit dem Upstream-Repository zu synchronisieren. Es ging nie darum die lokale Kopie mit dem Repository auf Github zu synchronisieren. Gituser schrieb: > Wenn du alles verbastelt hast, geht natürlich auch immer git reset. Schön, das setzt aber nur den Fork zurück und nicht etwa auf den aktuellen Stand des Upstream Repositories.
Rudolph R. schrieb: > Wieso Origin? > Es geht doch darum das Repository mit dem Upstream-Repository zu > synchronisieren. > > Es ging nie darum die lokale Kopie mit dem Repository auf Github zu > synchronisieren. Du kannst nicht direkt ein remote modifizieren. Das ist nicht vorgesehen und auch nie sinnvoll. Es wird immer alles lokal gemacht und dann per push/pull mit dem remote synchronisiert. Stichwort: Dezentrale Versionsverwaltung. Deshalb checke den Branch, den du modifizieren willst, lokal aus (nachdem du lokal synchronisiert hast mit git fetch) und mache was du machen willst. Dann pushe mit git push (-f). Fertig. Wichtig: Vorher die genannten Grundlagenkapitel im Buch lesen.
Rudolph R. schrieb: > Schön, das setzt aber nur den Fork zurück und nicht etwa auf den > aktuellen Stand des Upstream Repositories. Hast du dein upstream nicht als remote eingetragen? git remote add upstream URL_VON_UPSTREAM git reset upstream/master alternativ auch: git rebase upstream/master git push -f
Okay, mal mit git clone den Branch frisch lokal auf die Platte gezogen. git remote -v Okay, origin ist gesetzt und die URL anders als ich dachte. git remote add upstream https://github.com/marcio-ao/Marlin.git git remote -v sieht okay aus git reset upstream git reset upstream/master git reset upstream/bugfix-2.0.x-with-ftdi-eve-touchscreen -> fatal: ambignous argument '...' unknown revision or path in the working tree. git rebase upstream/bugfix-2.0.x-with-ftdi-eve-touchscreen git rebase upstream/master -> fatal Needed a single revision invalid upstream na denn. git fetch upstream git rebase upstream/bugfix-2.0.x-with-ftdi-eve-touchscreen Jetzt ist was passiert und es sieht so aus als ob die lokale Kopie auf dem Stand von dem Upstream-Repository wäre. git push -> error: failed to push some refs to ... hint: Updates were rejected beause the tip of your current branch is behind its remote counterpart. Integrate the remote changes (e.g. 'git pull ...') befor pushing again. git pull -> VIM Eingabe für Commit-Kommentar "Merge made by the 'recursive' strategy. git push Die lokale Kopie landet auf Github und sieht so aus als ob die identisch ist mit dem Branch im Upstream Repository. Allerdings: This branch is 3 commits ahead of marcio-ao:bugfix-2.0.x-with-ftdi-eve-touchscreen. Schön, jetzt sind die Dateien scheinbar *möglichwerweise* vielleicht wieder synchron mit dem Upstream Repository, weil das so aussieht und trotzdem drei Commits weiter. Wenn ich davon jetzt einen Branch ableite für den Pull-Request ist Github zurecht erstmal verwirrt da es den Branch im Upstream-Repository nicht gibt und zeigt an wie weit das weg ist vom Master-Branch, macht ja nichts. Aber wenn ich dafür einen Pull-Request erstelle gegen den Ziel-Branch ohne wirklich was geändert zu haben, dann will Github die inzwischen drei Commits ansetzen mit denen ich lediglich die Repositories synchronisiert habe -> unlustig. Also unterm Strich immer noch, es funktioniert nicht zwei Repositories sauber zu Synchronisieren.
Rudolph R. schrieb: > git fetch upstream > git rebase upstream/bugfix-2.0.x-with-ftdi-eve-touchscreen > > Jetzt ist was passiert Es ist nicht einfach nur "was passiert". Mit dem fetch hast du erst alle Daten von Upstream lokal geladen und bekannt gemacht. Bitte bitte die Kapitel aus dem Buch lesen. Git ist ein dezentrales System. Das zu verstehen ist wichtig. >git push >-> error: failed to push some refs to ... git push -f >git pull Falsch! >trotzdem drei Commits weiter. Weil du einen git pull gemacht hast. Bitte Buch lesen und verstehen. >Also unterm Strich immer noch, es funktioniert nicht zwei Repositories sauber zu Synchronisieren. Kein pull machen, sondern nur reset/rebase. Dann push -f.
Gituser schrieb: >>git push >>-> error: failed to push some refs to ... > > git push -f Verlixt, ja, ein forced-push, macht Sinn und hatte ich überlesen. Danke! Nach einem erneuten git rebase und git push -f steht da jetzt endlich "This branch is even with marcio-ao:bugfix-2.0.x-with-ftdi-eve-touchscreen.". Geht also doch, super, das macht die Geschichte etwas leichter. >>git pull > > Falsch! Nur weil git das vorgeschlagen hat... >>trotzdem drei Commits weiter. > > Weil du einen git pull gemacht hast. > Bitte Buch lesen und verstehen. Zumindest für den Moment habe ich jetzt alles zusammen was ich brauche und weiss mehr über Git als ich je wissen wollte.
Rudolph R. schrieb: > Nur weil git das vorgeschlagen hat... Die Vorschläge von git passen meistens. Aber git kann eben auch keine Gedanken lesen. Generell nimmt git an, dass man eher kein rebase machen will, oder sonst irgendwie die history modifizieren will. Das ist einfach ein "safe default", mit dem man sich am wenigsten kaputt macht. Sollte man sich doch mal was kaputt machen, gibts aber auch noch Tools zum Retten, wie z.B. git reflog. Ein komplett neues clone ist nie notwendig. Auch wenn es zugegeben für Anfänger oft der einfachere Weg ist. :) Aber wenn man einmal verstanden hat, wie git funktioniert, kommt man auf solche Ideen nicht mehr.
Hater schrieb: > Nico W. schrieb: >> Die meisten Gituser nutzen Rebase selten bis nie, arbeiten eher mit nem >> Merge bzw. pull-Requests. Ich möchte keinen Merge. Ich möchte eine >> komplette lineare History. > > Falsch. Aber so richtig. Nichts anderes wollte ich damit aussagen. Das ist nicht meine Vorgehensweise, sondern eine, die ich häufig gesehen habe. Ich sorge dafür das mein Arbeitsbranch mit dem Master/Experimental in einem linearen Zusammenhang steht. Meine Commits sollen am Ende on top auf das Master passen können. Hierzu nutze ich das angegebene Script, da es mir die Arbeit erleichtert. Bisher habe ich meistens nur gehört das ich 'alles Verkehrt' mache, allerdings vermisse ich stark, was genau der 'richtige' Weg ist. Mein normaler Workflow:
1 | git checkout master/experimental |
2 | git fetch |
3 | git pull |
4 | git checkout -b work_on_feature_xy |
5 | git add -u |
6 | git commit -m "my new feature" |
7 | git rebase master/experimental |
8 | git checkout master/experimental |
9 | git rebase work_on_feature_xy (oder git pull . work_on_feature_xy, beim rebase wird automatisch hier ein fast forward erzeugt) |
10 | git push |
Nico W. schrieb: > git rebase work_on_feature_xy Ich finde es sehr merkwürdig, dass du hier rebase verwendest. Ich habe das auch sonst noch nie gesehen. Warum nicht git merge oder eben einen lokalen pull? Das bewahrt dich auch vor Fehlern, falls du vergisst den branch vorher auf master zu rebasen. Wenn du git merge --ff-only verwendest, kannst du auch den Abbruch forcieren, falls kein FF möglich ist. Mit rebase tappst du stattdessen in die Falle.
Bewahren muss mich nichts bei git. Es ist ja nie was verloren. Reflog, Reset und co sei Dank. Und wenn ich nen rebase verkehrt setze breche ich ihn ab. Jedoch der einzige Grund warum ich keinen lokalen Pull gemacht habe, ich kannte es bisher einfach nicht. Aber ich bin nicht lernresistent. Ich werde Mal ein wenig damit arbeiten.
Beitrag #5437242 wurde von einem Moderator gelöscht.
Beitrag #5437275 wurde von einem Moderator gelöscht.
Beitrag #5437331 wurde von einem Moderator gelöscht.
Beitrag #5437373 wurde von einem Moderator gelöscht.
Beitrag #5437408 wurde von einem Moderator gelöscht.
Beitrag #5437410 wurde von einem Moderator gelöscht.
Beitrag #5437413 wurde von einem Moderator gelöscht.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.