Git

4.1 Verteiltes Arbeiten mit Git - Verteilte Arbeitsabläufe

Jetzt, wo Sie ein entferntes Repository als Ort eingerichtet haben, wo alle Entwickler ihren Code miteinander teilen können, und Sie mit den grundlegenden Git-Anweisungen innerhalb eines lokalen Arbeitsablaufs vertraut sind, werden wir uns anschauen, wie Sie einige der verteilten Arbeitsabläufe anwenden können, die Git Ihnen ermöglicht.

In diesem Kapitel werden Sie sehen, wie Sie mit Git in einer verteilten Umgebung als Mitarbeiter und als Integrator arbeiten. Das bedeutet, Sie werden erfahren, wie Sie Quelltext erfolgreich zu einem Projekt besteuern und wie Sie es sich und dem Projektbetreiber dabei so leicht wie möglich machen, und wie Sie selbst erfolgreich ein Projekt pflegen, an dem mehrere Entwickler beteiligt sind.

Verteilte Arbeitsabläufe

Im Gegensatz zu zentralisierten Versionsverwaltungen (CVCSs) ermöglicht Ihnen der dezentrale Charakter von Git, sehr viel flexibler darin zu sein, wie die Entwicklern bei Projekten zusammenarbeiten. In zentralisierten Systemen fungieren alle Entwickler als gleichwertige Netzknoten, die mehr oder weniger in der gleichen Art und Weise an einem zentralen Knotenpunkt arbeiten. In Git dagegen ist jeder Entwickler potentiell beides - Netzknoten und zentraler Knotenpunkt, d. h. jeder Entwickler kann sowohl Code zu anderen Repositories beitragen als auch selbst ein öffentliches Repository unterhalten, auf welchem widerum andere Ihre Arbeit aufbauen und an dem sie mitarbeiten können. Das eröffnet eine Fülle von möglichen Arbeitsabläufen für Ihr Projekt, weshalb wir einige gebräuchliche Musterbeispiele betrachten werden, welche sich diese Flexibilität zu Nutze machen. Wir werden auf die Stärken und möglichen Schwächen der einzelnen Entwürfe eingehen; Sie können einen einzelnen davon auswählen, um ihn zu nutzen, oder Sie können die Funktionalitäten von allen miteinander kombinieren.

Zentralisierte Arbeitsabläufe

In einem zentralisierten System gibt es im Allgemeinen ein einziges Modell der Zusammenarbeit - der zentralisierte Arbeitsablauf. Ein zentraler Knotenpunkt (oder Repository) kann Code von anderen akzeptieren und übernehmen, und alle Beteiligten synchronisieren ihre Arbeit damit. Eine Reihe von Entwicklern sind Netzknoten - Abnehmer von diesem Knotenpunkt - und synchronisieren ihre Arbeit mit diesem einen, zentralen Punkt.

Zentralisierter Arbeitsablauf.
Figure 55. Zentralisierter Arbeitsablauf.

Das bedeutet, wenn zwei Entwickler ein Repository vom zentralen Knotenpunkt klonen und beide lokal Änderungen vornehmen, dann kann der Entwickler, welcher als erster seine Änderungen ins zentrale Repository hochladen möchte, dies ohne Probleme tun. Der zweite Entwickler muss jedoch zunächst die Änderungen des ersten Entwicklers bei sich einfließen lassen, bevor er seine eigenen Änderungen hochladen kann, damit er die Änderungen des ersten Entwicklers nicht überschreibt. Dieses Prinzip ist sowohl für Git zutreffend als auch für Subversion (oder irgendein CVCS), und dieses Modell funktioniert bei Git vollkommen einwandfrei.

Wenn Sie in Ihrer Firma oder in Ihrem Team bereits mit einem zentralisierten Arbeitsablauf vertraut sind, können Sie einfach so weitermachen und diesen Arbeitsablauf mit Git realisieren. Richten Sie einfach ein einziges Repository ein und geben Sie jedem in Ihrem Team Schreibzugriff („push access“). Git sorgt dann dafür, dass niemand die Arbeit von anderen überschreiben kann. Sagen wir, Jessica und John beginnen mit der Arbeit zur selben Zeit. John beendet seine Änderungen und lädt diese auf den Server hoch. Dann versucht Jessica, ihre Änderungen hochzuladen, aber der Server weist diese zurück. Ihr wird mitgeteilt, dass sie versucht hat, “non-fast-forward”-Änderungen hochzuladen und dass sie dazu nicht in der Lage ist, bevor sie nicht die Änderungen des anderen Entwicklers heruntergeladen und mit ihren zusammengeführt hat. Viele Leute mögen diesen Arbeitsablauf, weil sie mit dem Paradigma bereits vertraut sind und sich damit wohl fühlen.

<<<<<<< HEAD Dies ist auch nicht auf kleine Teams beschränkt. Mit dem Branching-Modell von Git ist es möglich, dass hunderte von Entwicklern an einem einzelnen Projekt mittels dutzenden von Branches gleichzeitig erfolgreich arbeiten.

This is also not limited to small teams. With Git’s branching model, it’s possible for hundreds of developers to successfully work on a single project through dozens of branches simultaneously. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

==== Arbeitsablauf mit Integrationsmanager

<<<<<<< HEAD Weil Git es Ihnen ermöglicht, mehrere entfernte Repositories zu betreiben, ist es möglich, einen Arbeitsablauf zu gestalten, in dem jeder Entwickler Schreibzugriff auf sein eigenes öffentliches Repository hat und Lesezugriff auf die Repositories von allen anderen. Dieses Szenario beinhaltet häufig ein anerkanntes Repository, welches das “offizielle” Projekt darstellt. Um Änderungen zu einem solchen Projekt beizusteuern, können Sie Ihren eigenen öffentlichen Klon des Projektes anlegen und Ihre Änderungen dorthin hochladen. Anschließend können Sie den Betreiber des Haupt-Repositories bitten, Ihre Änderungen in sein Repository zu übernehmen. Der Betreiber kann dann Ihr Repository als ein entferntes Repository auf seinem Rechner hinzufügen, Ihre Änderungen lokal testen, diese in einen seiner Branches einfließen lassen und dann in sein öffentliches Repository hochladen. Dieser Prozess läuft wie folgt ab (siehe Arbeitsablauf mit Integrationsmanager.):

  1. Der Projektbetreiber lädt in sein öffentliches Repository hoch.

  2. Ein Mitarbeiter klont das Repository und nimmt Änderungen daran vor.

  3. Der Mitarbeiter lädt diese in sein eigenes öffentliches Repository hoch.

  4. Der Mitarbeiter schickt dem Betreiber eine E-Mail und bittet darum, die Änderungen zu übernehmen.

  5. Der Betreiber fügt das Repository des Mitarbeiters als ein entferntes Repository hinzu und führt die Änderungen lokal zusammen.

  6. Der Betreiber lädt die zusammengeführten Änderungen in das Haupt-Repository hoch.

Because Git allows you to have multiple remote repositories, it’s possible to have a workflow where each developer has write access to their own public repository and read access to everyone else’s. This scenario often includes a canonical repository that represents the “official” project. To contribute to that project, you create your own public clone of the project and push your changes to it. Then, you can send a request to the maintainer of the main project to pull in your changes. The maintainer can then add your repository as a remote, test your changes locally, merge them into their branch, and push back to their repository. The process works as follows (see Arbeitsablauf mit Integrationsmanager.):

  1. The project maintainer pushes to their public repository.

  2. A contributor clones that repository and makes changes.

  3. The contributor pushes to their own public copy.

  4. The contributor sends the maintainer an email asking them to pull changes.

  5. The maintainer adds the contributor’s repo as a remote and merges locally.

  6. The maintainer pushes merged changes to the main repository. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Arbeitsablauf mit Integrationsmanager.
Figure 56. Arbeitsablauf mit Integrationsmanager.

Dies ist ein sehr gewöhnlicher Arbeitsablauf bei hub-basierten Werkzeugen wie GitHub oder GitLab, wo es sehr einfach ist, ein Projekt zu “forken” und Ihre Änderungen in Ihren eigenen Fork hochzuladen, wo diese jeder einsehen kann. Einer der Hauptvorteile dieser Vorgehensweise ist, dass Sie an Ihrem Fork weiterarbeiten können und der Betreiber des Haupt-Repositorys Ihre Änderungen jederzeit übernehmen kann. Mitarbieter müssen nicht darauf warten, dass der Betreiber ihre Änderungen einarbeitet – jeder Beteiligte kann in seinem eigenen Tempo arbeiten.

Arbeitsablauf mit Diktator und Leutnants

<<<<<<< HEAD Dies ist eine Variante eines Arbeitsablaufs mit vielen Repositories. Sie wird normalerweise bei sehr großen Projekten mit hunderten von Mitarbeitern verwendet; ein bekanntes Beispiel ist der Linux Kernel. Verschiedene Integrationsmanager sind zuständig für bestimmte Teile des Repositorys; sie werden Leutnants genannt. Alle Leutnants haben wiederum einen Integrationsmanager, der als der wohlwollende Diktator (benevolent dictator) bezeichnet wird. Das Repository des wohlwollenden Diktators dient als das Referenzrepository, aus dem alle Beteiligten ihre eigenen Repositories aktualisieren müssen. Dieser Prozess funktioniert wie folgt (siehe Arbeitsablauf mit wohlwollendem Diktator.):

  1. Normale Entwickler arbeiten an ihren Themenbranches und fügen Ihre Arbeit an der Spitze des master-Branches mittels Rebase ein. Der master-Branch ist der Branch des Diktators.

  2. Die Leutnants führen die Themenbranches der Entwickler mit ihren master-Branches zusammen.

  3. Der Diktator führen die master-Branches der Leutnants mit seinem eigenen master-Branch zusammen.

  4. Der Diktator lädt seinen master-Branch ins Referenzrepository hoch, damit die anderen Entwickler darauf Rebase durchführen können.

This is a variant of a multiple-repository workflow. It’s generally used by huge projects with hundreds of collaborators; one famous example is the Linux kernel. Various integration managers are in charge of certain parts of the repository; they’re called lieutenants. All the lieutenants have one integration manager known as the benevolent dictator. The benevolent dictator pushes from his directory to a reference repository from which all the collaborators need to pull. The process works like this (see Arbeitsablauf mit wohlwollendem Diktator.):

  1. Regular developers work on their topic branch and rebase their work on top of master. The master branch is that of the reference directory to which the dictator pushes.

  2. Lieutenants merge the developers' topic branches into their master branch.

  3. The dictator merges the lieutenants' master branches into their master branch.

  4. The dictator pushes their master to the reference repository so the other developers can rebase on it. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Arbeitsablauf mit wohlwollendem Diktator.
Figure 57. Arbeitsablauf mit wohlwollendem Diktator.

Diese Art Arbeitsablauf ist nicht weit verbreitet, kann aber bei sehr großen Projekten oder in stark hierarchischen Umgebungen sehr nützlich sein. Er ermöglicht es dem Projektleiter (dem Diktator), Arbeit in großem Umfang zu delegieren und große Teilbereiche von Code an verschiedenen Punkten einzusammeln, bevor diese integriert werden.

==== Zusammenfassung Arbeitsabläufe

Dies sind einige häufig verwendete Arbeitsabläufe, die mit verteilten Systemen wie Git möglich sind, aber Sie können sehen, dass viele Variationen möglich sind, um genau zu Ihrem speziellen Arbeitsablauf in der realen Welt zu passen. Jetzt, da Sie (hoffentlich) bestimmen können, welche Kombination von Arbeitsabläufen bei Ihnen funktionieren würde, werden wir einige spezifischere Beispiele davon betrachten, wie man die Hauptaufgaben durchführen kann, welche die unterschliedliche Abläufe ausmachen. Im nächsten Abschnitt erfahren Sie etwas über gängige Formen der Mitarbeit an einem Projekt.

=== An einem Projekt mitarbeiten

<<<<<<< HEAD Die größte Schwierigkeit bei der Beschreibung der Mitarbeit an einem Projekt besteht darin, dass es eine große Anzahl von Variationen gibt, wie dies geschehen kann. Da Git sehr flexibel ist, bietet es den Menschen viele Möglichkeiten der Zusammenarbeit, und es ist problematisch zu beschreiben, wie Sie mitarbeiten sollten, da jedes Projekt ein bisschen anders ist. Einige der variablen Größen dabei sind die Anzahl der aktiven Mitarbeiter, der gewählte Arbeitsablauf, Ihre Zugriffsrechte und möglicherweise eine externe Methode der Mitarbeit.

Die erste variable Größe ist die Anzahl der aktiven Mitarbeiter - wie viele Nutzer steuern aktiv Code zu diesem Projekt bei und wie häufig? In vielen Fällen gibt es zwei oder drei Entwickler mit ein paar Commits pro Tag, oder auch weniger bei irgendwie ruhenden Projekten. Bei größeren Firmen oder Projekten kann die Anzahl der Entwickler in die Tausende reichen mit hunderten oder tausenden eingehenden Commits pro Tag. Das ist deshalb von Bedeutung, da Sie mit einer wachsenden Anzahl von Entwicklern auch sicherstellen müssen, dass sich der Code problemlos anwenden lässt und leicht zusammengeführt werden kann. Änderungen, die Sie übermitteln, können sich als überflüssig oder dysfunktional erweisen durch Beiträge, die inzwischen eingefügt wurden, während Sie noch an ihren Änderungen arbeiteten oder darauf warteten, dass diese geprüft oder angewendet werden. Wie können Sie Ihren Code permanent auf dem neusten Stand halten und dafür sorgen, dass Ihre Commits gültig sind?

Die nächste Variable ist der für das Projekt verwendete Arbeitsablauf. Ist es ein zentralisierter Arbeitsablauf, in dem jeder Entwickler die gleichen Schreibrechte auf die Hauptentwicklungslinie hat? Gibt es bei dem Projekt einen Projektbetreiber oder Integrationsmanager, der alle Patches prüft? Werden die Patches durch eine bestimmte Gruppe oder öffentlich, z. B. durch die Community, geprüft? Sind Sie selbst an diesem Prozess beteiligt? Gibt es ein Leutnant-System und müssen Sie Ihre Arbeit zunächst an einen solchen übermitteln?

Eine weiteres Thema sind ihre Commit-Zugriffsrechte. Der erforderliche Arbeitsablauf, um Änderungen zu einem Projekt beizusteuern, ist ein ganz anderer, wenn Sie über Schreibrechte verfügen, als wenn das nicht der Fall ist. Und wenn Sie keine Schreibrechte haben, in welcher Form müssen Sie ihre Änderungen bei diesem Projekt vorzugsweise übermitteln? Gibt es dafür überhaupt eine Richtlinie? Wie umfangreich sind die Änderungen, die Sie jeweils beisteuern? Und wie häufig tun Sie das?

All diese Aspekte haben Einfluss darauf, wie Sie effektiv an einem Projekt mitarbeiten können und welche Arbeitsabläufe bevorzugt werden oder verfügbar für Sie sind. Wir werden verschiedene Aspekte davon in einer Reihe von Fallbeispielen betrachten, wobei wir mit simplen Beispielen anfangen und später komplexere Szenarios besprechen. Sie sollten in der Lage sein, anhand dieser Beispiele die spezifischen Arbeitsabläufe zu erstellen, die Sie in der Praxis benötigen.

The main difficulty with describing how to contribute to a project is that there are a huge number of variations on how it’s done. Because Git is very flexible, people can and do work together in many ways, and it’s problematic to describe how you should contribute – every project is a bit different. Some of the variables involved are active contributor count, chosen workflow, your commit access, and possibly the external contribution method.

The first variable is active contributor count – how many users are actively contributing code to this project, and how often? In many instances, you’ll have two or three developers with a few commits a day, or possibly less for somewhat dormant projects. For larger companies or projects, the number of developers could be in the thousands, with hundreds or thousands of commits coming in each day. This is important because with more and more developers, you run into more issues with making sure your code applies cleanly or can be easily merged. Changes you submit may be rendered obsolete or severely broken by work that is merged in while you were working or while your changes were waiting to be approved or applied. How can you keep your code consistently up to date and your commits valid?

The next variable is the workflow in use for the project. Is it centralized, with each developer having equal write access to the main codeline? Does the project have a maintainer or integration manager who checks all the patches? Are all the patches peer-reviewed and approved? Are you involved in that process? Is a lieutenant system in place, and do you have to submit your work to them first?

The next variable is your commit access. The workflow required in order to contribute to a project is much different if you have write access to the project than if you don’t. If you don’t have write access, how does the project prefer to accept contributed work? Does it even have a policy? How much work are you contributing at a time? How often do you contribute?

All these questions can affect how you contribute effectively to a project and what workflows are preferred or available to you. We’ll cover aspects of each of these in a series of use cases, moving from simple to more complex; you should be able to construct the specific workflows you need in practice from these examples. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Richtlinien für Commits

Bevor wir damit beginnen, spezifische Anwendungsfälle zu betrachten, hier noch eine kurze Anmerkung zu Commit-Nachrichten. Ein gute Richtlinie für das Erzeugen von Commits zu haben und sich daran zu halten, macht die Arbeit mit Git und die Zusammenarbeit mit anderen um vieles leichter. Das Git-Projekt stellt ein Dokument bereit, welches eine Reihe von guten Tipps für das Erzeugen von Commits zum Übermitteln von Patches beinhaltet. Sie können die Tipps in der Datei Documentation/SubmittingPatches im Git-Quellcode nachlesen.

<<<<<<< HEAD Als Erstes wollen Sie keinerlei Leerzeichenfehler übermitteln. Git bietet eine einfache Möglichkeit, dies zu überprüfen - bevor Sie einen Commit vornehmen, führen Sie die Anweisung git diff --check aus, welche mögliche Leerzeichenfehler erkennt und für Sie auflistet.

Ausgabe von `git diff --check`.
Figure 58. Ausgabe von git diff --check.

Wenn Sie diese Anweisung vor einem Commit ausführen, können Sie erkennen, ob Sie dabei sind, Leerzeichenfehler zu übermitteln, welche andere Entwickler verärgern könnten.

Als Nächstes, versuchen Sie, aus jedem Commit einen logisch getrennten Satz von Änderungen zu machen. Wenn Sie können, versuchen Sie, Ihre Änderungen leicht verdaulich zu machen - arbeiten Sie nicht ein ganzes Wochenende an fünf verschiedenen Themen und übermitteln Sie dann all diese Änderungen in einem massiven Commit am Montag. Auch wenn Sie am Wochenende keine Commits durchführen, nutzen Sie am Montag die Staging Area, um Ihre Änderungen aufzuteilen in wenigstens einen Commit für jeden Teilaspekt mit jeweils einer sinnvollen Nachricht. Wenn einige der Änderungen die selbe Datei modifizieren, benutzen Sie die Anweisung git add --patch, um Dateien partiell zur Staging Area hinzuzufügen (detailiert dargestellt im Abschnitt [_interactive_staging]). Der Schnappschuss vom Projekt an der Spitze des Branches ist der Selbe, ob Sie einen oder fünf Commits durchgeführt haben, solange nur all die Änderungen irgendwann hinzugefügt werden. Versuchen Sie also, die Dinge zu vereinfachen für Ihre Entwicklerkollegen, die Ihre Änderungen begutachten müssen. Dieser Ansatz macht es außerdem einfacher, einen Satz von Änderungen zu entfernen oder rückgängig zu machen, falls das später nötig wäre. [_rewriting_history] beschreibt eine Reihe nützlicher Git-Tricks zum Umschreiben des Verlaufs oder um interaktiv Dateien zur Staging Area hinzuzufügen. Verwenden Sie diese Werkzeuge, um einen sauberen und leicht verständlichen Verlauf aufzubauen, bevor Sie Ihre Arbeit jemand anderem schicken.

Ein weitere Sache, die Sie nicht vergessen sollten, ist die Commit-Nachricht. Wenn man sich angewöhnt, aussagekräftige und hochwertige Commit-Nachrichten zu schreiben, ist die Benutzung von Git viel einfacher und es erleichtert die Zusammenarbeit. In der Regel sollte Ihre Commit-Nachricht mit einer einzelnen Zeile anfangen, die nicht länger als 50 Zeichen sein sollte und die Änderungen kurz und bündig beschreibt, gefolgt von einer leeren Zeile, welcher eine ausführlichere Beschreibung der Änderungen folgt. Das Git-Projekt fordert, dass die detailliertere Erklärung Ihre Motivation für die Änderungen beinhaltet und deren Implementierung dem vorhergehenden Verhalten gegenüberstellt. Das ist eine gute Richtlinie, an die man sich halten sollte. Es empfiehlt sich außerdem, die Gegenwartsform des Imperativ in diesen Nachrichten zu benutzen. Mit anderen Worten, nutzen Sie Anweisungen. Anstatt “Ich habe Test hinzugefügt für” oder “Tests hinzufügend für” benutzen Sie “Füge Tests hinzu für”. Hier ist ein Muster, welches ursprünglich von Tim Pope stammt:

Kurze (50 Zeichen oder weniger) Zusammenfassung der Änderungen
=======
First, you don't want to submit any whitespace errors.
Git provides an easy way to check for this – before you commit, run `git diff --check`, which identifies possible whitespace errors and lists them for you.

.Output of `git diff --check`.
image::images/git-diff-check.png[Output of `git diff --check`.]

If you run that command before committing, you can tell if you're about to commit whitespace issues that may annoy other developers.

Next, try to make each commit a logically separate changeset.
If you can, try to make your changes digestible – don't code for a whole weekend on five different issues and then submit them all as one massive commit on Monday.
Even if you don't commit during the weekend, use the staging area on Monday to split your work into at least one commit per issue, with a useful message per commit.
If some of the changes modify the same file, try to use `git add --patch` to partially stage files (covered in detail in <<_interactive_staging>>).
The project snapshot at the tip of the branch is identical whether you do one commit or five, as long as all the changes are added at some point, so try to make things easier on your fellow developers when they have to review your changes.
This approach also makes it easier to pull out or revert one of the changesets if you need to later.
<<_rewriting_history>> describes a number of useful Git tricks for rewriting history and interactively staging files – use these tools to help craft a clean and understandable history before sending the work to someone else.

The last thing to keep in mind is the commit message.
Getting in the habit of creating quality commit messages makes using and collaborating with Git a lot easier.
As a general rule, your messages should start with a single line that's no more than about 50 characters and that describes the changeset concisely, followed by a blank line, followed by a more detailed explanation.
The Git project requires that the more detailed explanation include your motivation for the change and contrast its implementation with previous behavior – this is a good guideline to follow.
It's also a good idea to use the imperative present tense in these messages.
In other words, use commands.
Instead of ``I added tests for'' or ``Adding tests for,'' use ``Add tests for.''
Here is a http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[template originally written by Tim Pope]:

[source,text]
----
Short (50 chars or less) summary of changes
>>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Detailliert erklärender Text, wenn nötig. Beschränken Sie
diesen auf ca. 72 Zeichen. In Abhängigkeit vom Kontext wird
die erste Zeile manchmal wie die Betreff-Zeile einer E-Mail
behandelt und der übrige Text wie der Textkörper der
Nachricht. Die leere Zeile, welche die Zusammenfassung vom
Text trennt, ist kritisch (außer Sie lassen den Text komplett
weg); Werkzeuge wie Rebase können durcheinander kommen, wenn
Sie beide gleichzeitig verwenden.

Weitere Absätze folgen jeweils nach leeren Zeilen.

  - Aufzählungspunkte kann man auch verwenden

<<<<<<< HEAD
  - Typischer Weise nutzt man Bindestriche oder Sternchen
    als Aufzählungszeichen, denen ein einzelnes Leerzeichen
	vorangestellt wird, die einzelnen Punkte werden durch
    leere Zeilen getrennt, die Konventionen variieren hier
  • Typically a hyphen or asterisk is used for the bullet, preceded by a single space, with blank lines in between, but conventions vary here

>>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Wenn alle Ihre Commit-Nachrichten so aussehen, werden die Dinge für Sie und die Entwickler, mit denen Sie zusammenarbeiten, viel einfacher sein.
Das Git-Projekt selbst hat wohl-formatierte Commit-Nachrichten - führen Sie mal die Anweisung `git log --no-merges` aus, um zu sehen, wie ein angenehm formatierter Commit-Verlauf eines Projektes aussieht.

In den folgenden Beispielen und fast überall in diesem Buch finden Sie der Kürze halber keine angenehm formatierten Meldungen wie diese. Stattdessen wird die Anweisung `git commit` zusammen mit der Option `-m` verwendet.
Also folgen Sie meinen Worten und nicht meinem Beispiel.

<<<<<<< HEAD

For the sake of brevity, the following examples, and most examples in other parts of this book, don’t have nicely-formatted messages like this; instead, we use the -m option to git commit. Do as we say, not as we do. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Vertrauliches kleines Team

Das einfachste Szenario, dem Sie sehr wahrscheinlich begegnen werden, ist ein vertrauliches Projekt mit einem oder zwei Entwicklern. “Private” in diesem Zusammenhang bedeutet "closed source" - nicht öffentlich zugänglich für die Außenwelt. Sie und die anderen Entwickler haben alle Schreibzugriff auf das Repository.

Sie können sich in diesem Umfeld an einen Arbeitsablauf halten, den Sie genauso auch bei Subversion oder einem anderen zentralisierten System verwenden könnten. Sie genießen dann immer noch die Vorteile von Dingen, wie Commits offline durchführen zu können und erheblich einfacher Branches anzulegen und zusammenzuführen, aber der Arbeitsablauf kann sehr ähnlich sein. Der Hauptunterschied ist, dass das Zusammenführen eher auf der Client-Seite stattfindet als auf dem Server beim Durchführen eines Commits. Lassen Sie uns betrachten, wie es aussehen könnte, wenn zwei Entwickler damit beginnen, an einem gemeinsamen Repository zu arbeiten. Der erste Entwickler, John, klont das Repository, nimmt eine Änderung vor und führt lokal einen Commit durch. (Die Protokoll-Nachrichten wurden in diesen Beispielen durch ... ersetzt, um das Ganze etwas zu kürzen.)

# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'remove invalid default value'
[master 738ee87] remove invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

Die zweite Entwicklerin, Jessica, tut das Selbe. Sie klont das Repository, ändert etwas und führt einen Commit durch.

# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Nun lädt Jessica ihre Arbeit auf den Server hoch:

# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

John versucht ebenfalls, seine Änderungen hochzuladen:

# John's Machine
$ git push origin master
To john@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'

John ist es nicht gestattet, seine Änderungen hochzuladen, weil Jessica inzwischen ihre hochgeladen hat. Dies zu verstehen, ist besonders wichtig, wenn Sie dem Umgang mit Subversion gewöhnt sind, weil Sie bemerkt haben werden, dass die beiden Entwickler nicht die gleiche Datei bearbeitet haben. Obwohl Subversion automatisch das Zusammenführen auf dem Server durchführt, wenn zwei verschiedene Dateien bearbeitet werden, müssen Sie die Commits bei Git lokal zusammenführen. John muss erst Jessicas Änderungen abholen und lokal mit seinen zusammenführen, bevor ihm das Hochladen gestattet wird.

$ git fetch origin
...
From john@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

Zu diesem Zeitpunkt sieht Johns lokales Repository ungefähr so aus:

John’s divergent history.
Figure 59. Johns abzweigender Verlauf.

John hat einen Bezug zu den Änderungen, welche Jessica hochgeladen hat, aber er muss diese erst mit seiner eigenen Arbeit zusammenführen, bevor es ihm gestattet ist, selbst hochzuladen.

$ git merge origin/master
Merge made by the 'recursive' strategy.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

Das Zusammenführen läuft problemlos - Johns Commit-Verlauf sieht jetzt so aus:

John’s repository after merging `origin/master`.
Figure 60. Johns Repository nach dem Zusammenführen mit origin/master.

Jetzt kann John seinen Code überprüfen, um sicherzustellen, dass dieser immer noch ordnungsgemäß funktioniert, und dann kann er seine neue, zusammengeführte Arbeit auf den Server hochladen:

$ git push origin master
...
To john@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

Schließlich sieht Johns Commit-Verlauf so aus:

John’s history after pushing to the `origin` server.
Figure 61. Johns Verlauf nach dem Hochladen auf den origin-Server.

Jesicca hat in der Zwischenzeit an einem Themenbranch gearbeitet. Sie hat einen Themenbranch namens issue54 erzeugt und auf diesem Branch drei Commits durchgeführt. Noch hat sie Johns Änderungen nicht vom Server abgeholt, sodass ihr Commit-Verlauf jetzt so aussieht:

Jessica’s topic branch.
Figure 62. Jessicas Themenbranch.

Jessica möchte ihren Stand mit Johns synchronisieren, also führt sie die Anweisung git fetch origin aus:

# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Das lädt alle Änderungen herunter, die John in der Zwischenzeit hochgeladen hat. Jessicas Verlauf sieht nun so aus:

Jessica’s history after fetching John’s changes.
Figure 63. Jessicas Verlauf nach dem Abholen von Johns Änderungen.

Jessica denkt, dass ihr Themenbranch fertig ist, aber sie möchte wissen, welche Änderung sie mit ihrer Arbeit zusammenführen muss, damit sie ihrerseits hochladen kann. Sie führt die Anweisung git log aus, um dies herauszufinden:

$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 16:01:27 2009 -0700

   remove invalid default value

<<<<<<< HEAD Bei der Syntax issue54..origin/master handelt es sich um einen log-Filter, der Git anweist, nur die Commits aufzulisten, welche auf dem letzteren Branch durchgeführt wurden (in diesem Fall origin/master) und die sich nicht auf dem ersten Branch befinden (in diesem Fall issue54). Wir werden uns diese Syntax detailliert in [_commit_ranges].

Fürs Erste können wir an der Ausgabe erkennen, dass es einen einzelnen Commit von John gibt, den Jessica noch nicht bei sich eingefügt hat. Dieser einzelne Commit modifiziert ihre lokalen Änderungen, wenn sie ihren Branch mit origin/master zusammenführt.

The issue54..origin/master syntax is a log filter that asks Git to only show the list of commits that are on the latter branch (in this case origin/master) that are not on the first branch (in this case issue54). We’ll go over this syntax in detail in [_commit_ranges].

For now, we can see from the output that there is a single commit that John has made that Jessica has not merged in. If she merges origin/master, that is the single commit that will modify her local work. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Jetzt kann Jessica ihren Themenbranch mit ihrem master-Branch zusammenführen, danach Johns Arbeit (origin/master) mit ihrem master-Branch zusammenführen und dann das Ganze auf den Server hochladen. Zuerst wechselt sie zu ihrem master-Branch, um alle diese Änderungen zu integrieren:

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

Sie kann entweder origin/master oder issue54 zuerst integrieren, da sie beide "stromaufwärts" angeordnet sind, spielt die Reihefolge keine Rolle. Der Snapshot am Ende sollte identisch sein, egal, welche Reihenfolge sie wählt, nur der Verlauf wird ein wenig anders sein. Sie entscheidet sich dafür, issue54 zuerst einfließen zu lassen.

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

Es treten keine Probleme auf; wie Sie sehen können, war es ein einfacher "Fast-Forward". Nun integriert Jessica die Arbeit von John (origin/master):

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Alles lässt sich sauber zusammenführen und Jessicas Verlauf sieht jetzt so aus:

Jessica’s history after merging John’s changes.
Figure 64. Jessicas Verlauf nach dem Zusammenführen mit Johns Änderungen.

Jetzt ist origin/master von Jessicas master-Branch aus erreichbar, sodass sie in der Lage sein sollte, erfolgreich hochladen zu können (vorausgesetzt, John hat nicht inzwischen schon wieder etwas hochgeladen):

$ git push origin master
...
To jessica@githost:simplegit.git
   72bbc59..8059c15  master -> master

Jeder Entwickler hat einige Commits durchgeführt und jeweils die Arbeiten des anderen mit den eigenen zusammengeführt.

Jessica’s history after pushing all changes back to the server.
Figure 65. Jessicas Verlauf nach dem Hochladen aller Änderungen auf den Server.

<<<<<<< HEAD Das ist einer der einfachsten Arbeitsabläufe. Sie arbeiten eine Weile, gewöhnlich an einem Themenbranch, und führen diesen mit ihrem master-Branch zusammen, wenn dieser soweit fertig ist, dass er integriert werden kann. Wenn Sie diese Arbeit mit anderen teilen wollen, führen Sie die Änderungen mit ihrem eigenen master-Branch zusammen, holen eventuelle Änderungen vom Branch origin/master ab und führen diese mit ihren master-Branch zusammen, und schließlich laden sie alles auf den master-Branch auf den Server hoch. Der generelle Ablauf sieht ungefähr so aus:

That is one of the simplest workflows. You work for a while, generally in a topic branch, and merge into your master branch when it’s ready to be integrated. When you want to share that work, you fetch and merge your master from origin/master if it has changed, and finally push to the master branch on the server. The general sequence is something like this: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

General sequence of events for a simple multiple-developer Git workflow.
Figure 66. Genereller Ablauf von Ereignissen für einen einfachen Arbeitsablauf mit mehreren Entwicklern.

Geführte vertrauliche Teams

In diesem Szenario werden Sie die Funktionen von Mitarbeitern in einem größeren, nicht öffentlich arbeitenden Team betrachten. Sie werden erfahren, wie Sie in einem Umfeld arbeiten können, wo in kleinen Gruppen an der Entwicklung einzelner Features gearbeitet wird und dann diese team-basierten Beiträge durch einen anderen Beteiligten integriert werden.

Sagen wir, John und Jessica arbeiten gerade zusammen an einem Feature, während Jessica und Josie gerade an einem zweiten arbeiten. Das Unternehmen benutzt in diesem Fall einen Typ des Arbeitsablaufs mit Integrationsmanager, bei dem die Arbeit der individuellen Gruppen nur durch bestimmte Mitarbeiter integriert wird und der master-Branch des Haupt-Repositorys auch nur durch eben diese Mitarbeiter aktualisiert werden kann. Die ganze Arbeit wird in diesem Szenario auf team-basierten Branches ausgeführt und später von den Integrationsmanagern zusammengeführt.

Lassen Sie uns Jessicas Arbeitsablauf betrachten, wie sie in diesem Umfeld parallel mit zwei verschiedenen Entwicklern an ihren beiden Features arbeitet. Vorausgesetzt, sie hat ihr Repository bereits geklont, entscheidet sie sich, zuerst an featureA zu arbeiten. Sie erzeugt einen neuen Branch für das Feature und arbeitet etwas daran:

# Jessica's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 files changed, 1 insertions(+), 1 deletions(-)

An diesem Punkt muss sie den Stand ihrer Arbeiten John mitteilen, also lädt sie ihre Commits von featureA-Branch auf den Server hoch. Jessica hat keine Schreibrechte auf dem master-Branch - den haben nur die Integrationsmanager - also muss sie auf einen anderen Branch hochladen, um mit John zusammenarbeiten zu können.

$ git push -u origin featureA
...
To jessica@githost:simplegit.git
 * [new branch]      featureA -> featureA

<<<<<<< HEAD Jessica sendet John eine E-Mail, um ihm mitzuteilen, dass einige Änderungen auf einen neuen Branch namens featureA hochgeladen hat und er nun einen Blick darauf werfen kann. Während sie auf ein Feedback von John wartet, entscheidet sich Jessica, mit der Arbeit an featureB zu beginnen - diesmal gemeinsam mit Josie. Am Anfang legt sie einen neuen Feature-Branch an, basierend auf dem master-Branch, welcher sich auf dem Server befindet (origin/master):

Jessica emails John to tell him that she’s pushed some work into a branch named featureA and he can look at it now. While she waits for feedback from John, Jessica decides to start working on featureB with Josie. To begin, she starts a new feature branch, basing it off the server’s master branch: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

# Jessica's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'

Jetzt führt Jessica eine Reihe von Commits auf dem featureB-Branch durch:

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 files changed, 5 insertions(+), 0 deletions(-)

Jessicas Repository sieht jetzt so aus:

Jessica’s initial commit history.
Figure 67. Jessicas ursprünglicher Commit-Verlauf.

<<<<<<< HEAD Jessica könnte ihre Arbeit jetzt hochladen, aber sie bekommt eine E-Mail von Josie, in der diese mitteilt, dass bereits ein Branch namens featureBee hochgeladen wurde, welcher einige erste Änderungen beinhaltet. Jessica muss also erst diese Änderungen mit ihren eigenen Änderungen zusammenführen, bevor sie selbst etwas hochladen kann. Sie kann Josies Änderungen mit git fetch herunterladen:

She’s ready to push up her work, but gets an email from Josie that a branch with some initial work on it was already pushed to the server as featureBee. Jessica first needs to merge those changes in with her own before she can push to the server. She can then fetch Josie’s changes down with git fetch: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ git fetch origin
...
From jessica@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Jessica kann jetzt dies mit den Änderungen, die sie vorgenommen hat, zusammenführen:

$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
 lib/simplegit.rb |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

Dabei gibt es ein kleines Problem - sie muss die zusammengeführten Änderungen in ihrem featureB-Branch in den featureBee-Branch auf dem Server hochladen. Sie kann dies erledigen, indem sie die Anweisung git push verwendet und dabei den lokalen Branch festlegt, gefolgt von einem Doppelpunkt (:), gefolgt vom Branch auf dem entfernten Server:

$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
   fba9af8..cd685d1  featureB -> featureBee

Das bezeichnet man als refspec. Siehe [_refspec] für detailliertere Diskussionen von Gits refspecs und verschiedenden Dingen, die Sie damit machen können. Beachten Sie auch die Option -u; das ist die Kurzform von --set-upstream, welche die Branches für ein einfacheres Hoch- und Herunterladen konfiguriert.

<<<<<<< HEAD Als Nächstes sendet John eine E-Mail an Jessica, um sie zu informieren, dass er einige Änderungen auf den featureA-Branch hochgeladen hat, und um sie zu bitten, diese zu überprüfen. Sie führt die Anweisung git fetch aus, um diese Änderungen herunter zu laden:

Next, John emails Jessica to say he’s pushed some changes to the featureA branch and asks her to verify them. She runs a git fetch to pull down those changes: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ git fetch origin
...
From jessica@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Um zu sehen, was geändert wurde, benutzt sie die Anweisung git log:

$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 19:57:33 2009 -0700

    changed log output to 30 from 25

Schließlich lässt sie Johns Änderungen in ihren eigenen featureA-Branch einfließen:

$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
 lib/simplegit.rb |   10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

Jessica möchte etwas optimieren, also führt sie wieder einen Commit durch und lädt dann das Ganze auf den Server hoch:

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Jessicas Commit-Verlauf sieht jetzt ungefähr so aus:

Jessica’s history after committing on a feature branch.
Figure 68. Jessicas Verlauf nach dem Commit auf den Feature-Branch.

Jessica, Josie und John informieren die Integrationsmanager, dass die Branches featureA und featureBee auf dem Server soweit fertiggestellt sind, um in die Hauptlinie integriert zu werden. Nachdem die Integrationsmanager diese Branches mit der Hauptlinie zusammengeführt haben, wird beim Abholen der Daten vom Server der neue Merge-Commit heruntergeladen, was den Commit-Verlauf dann so aussehen lässt:

Jessica’s history after merging both her topic branches.
Figure 69. Jessicas Verlauf nach dem Zusammenführen mit ihren beiden Themenbranches.

Viele Teams wechseln zu Git, weil es damit möglich ist, dass mehrere Teams parallel arbeiten können und die verschiedenen Entwicklungslinien erst später im Prozess zusammengeführt werden. Ein riesiger Vorteil von Git besteht darin, dass man in kleinen Untergruppen eines Teams über entfernte Branches zusammenarbeiten kann, ohne notwendigerweise das gesamte Team zu involvieren oder zu behindern. Die Reihenfolge bei dem Arbeitsablauf, den Sie gesehen haben, ist ungefähr folgende:

Basic sequence of this managed-team workflow.
Figure 70. Grundlegende Reihenfolge des Arbeitsablaufs bei einem geführten Team.

==== Verteiltes öffentliches Projekt

<<<<<<< HEAD An einem öffentlichen Projekt mitzuarbeiten, ist ein wenig anders. Da Sie keine Berechtigungen haben, die Branches des Projektes direkt zu aktualisieren, müssen Sie die Änderungen auf andere Art und Weise zu den Projektbetreibern bekommen. Dieses erste Beispiel beschreibt die Mitarbeit mittels "Forking" auf Git-Hosting-Servern, welche einfaches "Forking" unterstützen. Viele Hosting-Websites unterstützen dies (einschließlich GitHub, BitBucket, Google Code repo.or.cz und andere), und viele Projektbetreiber erwarten diese Art der Zuarbeit. Der nächste Abschnitt handelt von Projekten, welche die Abgabe von Patches bevorzugt via E-Mail akzeptieren.

Contributing to public projects is a bit different. Because you don’t have the permissions to directly update branches on the project, you have to get the work to the maintainers some other way. This first example describes contributing via forking on Git hosts that support easy forking. Many hosting sites support this (including GitHub, BitBucket, repo.or.cz, and others), and many project maintainers expect this style of contribution. The next section deals with projects that prefer to accept contributed patches via email. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Zunächst werden Sie vermutlich das Hauptrepository klonen wollen, einen Themenbranch anlegen für den Patch oder die Serie von Patches, die Sie beisteuern möchten, und dann darin arbeiten. Die Reihenfolge sieht dann in etwa so aus:

$ git clone (url)
$ cd project
$ git checkout -b featureA
# (work)
$ git commit
# (work)
$ git commit
Note

Es empfiehlt sich, die Anweisung git rebase -i zu verwenden, um die verschiedenen Commits zu einem einzigen zusammenzufassen oder um sie in anderer Weise neu zu arrangieren, sodass es für die Projektbetreiber leichter ist, die Änderungen zu überprüfen- – siehe [_rewriting_history] für weitere Informationen über interaktives Rebasing.

Wenn Sie mit der Arbeit an ihrem Branch fertig sind und Sie ihren Beitrag den Projektbetreibern zur Verfügung stellen wollen, gehen Sie auf die Projektseite und klicken auf den “Fork”-Button, um Ihren eigenen Fork des Projektes anzulegen, in den Sie dann schreiben können. Die URL des Repositorys dieses Forks müssen Sie dann als ein zweites, entferntes Repository (“remote”) einrichten, in diesem Beispiel hat es den Namen myfork:

$ git remote add myfork (url)

<<<<<<< HEAD Dann müssen Sie Ihre Änderungen dorthin hochladen. Am einfachsten ist es, den Themenbranch, an dem Sie gerade arbeiten, in Ihr Repository hochzuladen, anstatt ihn mit Ihrem master-Branch zusammenzuführen und diesen dann hochzuladen. Der Grund dafür ist, dass Sie Ihren master-Branch nicht zurücksetzen müssen, falls Ihre Änderungen nicht akzeptiert werden. Wenn die Projektbetreiber Ihre Änderungen übernehmen, ob mit merge, rebase oder cherry-pick, werden Sie diese schließlich sowieso zurückbekommen mittels git pull von deren Repository.

Then you need to push your work up to it. It’s easiest to push the topic branch you’re working on up to your repository, rather than merging into your master branch and pushing that up. The reason is that if the work isn’t accepted or is cherry-picked, you don’t have to rewind your master branch. (cherry-pick is covered in more detail in [_rebase_cherry_pick]). If the maintainers merge, rebase, or cherry-pick your work, you’ll eventually get it back via pulling from their repository anyhow: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ git push -u myfork featureA

<<<<<<< HEAD Wenn Sie Ihre Arbeit in Ihren Fork hochgeladen haben, müssen Sie den Projektbetreiber benachrichtigen. Dies wird häufig als “pull request” bezeichnet und Sie können diesen entweder direkt über die Webseite erzeugen - GitHub hat seinen eigenen “Pull Request”-Mechanismus, welchen wir in [_github] näher betrachten - oder Sie können die Anweisung git request-pull ausführen und die Ausgabe manuell per E-Mail an den Projektbetreiber schicken.

When your work has been pushed up to your fork, you need to notify the maintainer. This is often called a pull request, and you can either generate it via the website – GitHub has its own Pull Request mechanism that we’ll go over in [_github] – or you can run the git request-pull command and email the output to the project maintainer manually. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Die Anweisung request-pull nimmt den Ausgangsbranch, für den Ihre Änderungen bestimmt sind, und die URL des Git-Repositorys, von dem Ihre Änderungen heruntergeladen werden sollen, und gibt eine Zusammenfassung aller Änderungen aus, um deren Übernahme Sie bitten. Wenn Jessica z. B. einen “pull request” an John schicken will, und sie zwei Commits auf dem gerade hochgeladenen Themenbranch durchgeführt hat, kann sie diese Anweisung ausführen:

$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
  John Smith (1):
        added a new function

are available in the git repository at:

  git://githost/simplegit.git featureA

Jessica Smith (2):
      add limit to log function
      change log output to 30 from 25

 lib/simplegit.rb |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

<<<<<<< HEAD Die Ausgabe kann an die Projektbetreiber geschickt werden – sie sagt ihnen, auf welcher Stelle der Branch angelegt wurde, fasst die Commits zusammen und gibt an, aus welchem Fork oder Repository man die Änderungen herunterladen kann.

The output can be sent to the maintainer – it tells them where the work was branched from, summarizes the commits, and tells where to pull this work from. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Bei einem Projekt, wo Sie nicht selbst der Betreiber sind, ist es im Allgemeinen einfacher, einen Branch wie master zu haben, welcher immer den origin/master-Branch verfolgt, und Ihre eigenen Änderungen in Themenbranches vorzunehmen, die Sie leicht verwerfen können, wenn diese nicht akzeptiert werden. Wenn Sie Schwerpunkte Ihrer Arbeit in Themenbranches unterteilen, können Sie diese außerdem recht leicht auf den letzten Stand des Hauptrepositorys rebasen, falls das Hauptrepository in der Zwischenzeit weiter entwickelt wurde und Ihre Commits sich nicht mehr sauber anwenden lassen. Wollen Sie beispielsweise Änderungen zu einem weiteren Thema für das Projekt beisteuern, dann arbeiten Sie nicht weiter auf dem Themenbranch, den Sie gerade hochgeladen haben - sondern beginnen Sie von vorn vom master-Branch des Hauptrepositorys:

$ git checkout -b featureB origin/master
# (work)
$ git commit
$ git push myfork featureB
$ git request-pull origin/master myfork
# (email maintainer)
$ git fetch origin

Jedes Ihrer Themen befindet sich jetzt in einer Art Silo - ähnlich zu einer Patch Queue – sodass Sie diese neu schreiben, rebasen und ändern können, ohne dass die Themen sich gegemseitig stören oder voneinander abhängen:

Initial commit history with `featureB` work.
Figure 71. Ursprünglicher Commit-Verlauf bei der Arbeit an featureB.

Sagen wir, der Projektbetreiber hat eine Menge von anderen Patches übernommen und versucht, Ihren ersten Branch einfließen zu lassen, aber dieser lässt sich nicht mehr sauber anwenden. In diesem Fall können Sie Ihre Änderungen auf dem letzten Stand des origin/master-Branches mittels Rebase hinzufügen, die Konflikte für den Projektbetreiber beheben und Ihre Arbeit erneut einreichen:

$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA

Das schreibt Ihren Commit-Verlauf neu, sodass dieser jetzt so aussieht Commit-Verlauf nach dem Rebase von featureA..

Commit history after `featureA` work.
Figure 72. Commit-Verlauf nach dem Rebase von featureA.

Da Sie den Branch mittels Rebase hinzugefügt haben, müssen Sie die Anweisung git push mit der Option -f verwenden, um den featureA-Branch auf dem Server mit einem Commit ersetzen zu können, der nicht vom gegenwärtig letzten Commit des entfernten Branches abstammt. Eine Alternative dazu wäre, diese neuen Änderungen in einen anderen Branch auf dem Server hochzuladen (vielleicht namens featureAv2).

Schauen wir uns noch ein weiteres mögliches Szenario an: der Projektbetreiber hat sich Ihre Arbeit in Ihrem zweiten Branch angesehen und mag das Konzept, aber er bittet Sie, noch ein Detail an der Implementierung zu ändern. Sie werden die Gelegenheit außerdem nutzen, um Ihre Änderungen zu verschieben, damit diese auf dem aktuellen master-Branch des Projektes basieren. Sie legen dazu ausgehend vom aktuellen origin/master-Branch einen neuen Branch an, führen Ihre Änderungen aus featureB damit zusammen, lösen dabei jegliche Konflikte, erledigen die gewünschte Änderung an der Implementierung und laden das Ganze als neuen Branch hoch:

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
# (change implementation)
$ git commit
$ git push myfork featureBv2

<<<<<<< HEAD Die Option --squash fasst alle Änderungen des einfließenden Branches (featureB) zusammen und quetscht diese in einen Nicht-Merge-Commit an der Spitze des Branches, auf dem Sie sich gerade befinden. Die Option --no-commit weist Git außerdem an, nicht automatisch einen Commit anzulegen. Das ermöglicht Ihnen, sämtliche Änderungen aus einem anderen Branch zu übernehmen und dann weitere Änderungen vorzunehmen, bevor Sie einen neuen Commit aufzeichnen.

The --squash option takes all the work on the merged branch and squashes it into one changeset producing the repository state as if a real merge happened, without actually making a merge commit. This means your future commit will have one parent only and allows you to introduce all the changes from another branch and then make more changes before recording the new commit. Also the --no-commit option can be useful to delay the merge commit in case of the default merge process. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Jetzt können Sie dem Projektbetreiber eine Nachricht schicken, dass Sie die gewünschten Änderungen vorgenommen haben und dass er Ihre Änderungen in Ihrem featureBv2-Branch finden kann.

Commit history after `featureBv2` work.
Figure 73. Commit-Verlauf nach den Änderungen an featureBv2.

<<<<<<< HEAD ==== Öffentliches Projekt via E-Mail

==== Public Project over Email >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Viele Projekte haben festgelegte Verfahren, um Patches entgegenzunehmen - Sie werden sich mit den jeweiligen Regeln vertraut machen müssen, da diese bei jedem Projekt unterschiedlich sein werden. Da ist etliche ältere, große Projekte gibt, welche Patches über eine Mailingliste der Entwickler entgegennehmen, werden wir auf dieses Beispiel als Nächstes eingehen.

<<<<<<< HEAD Der Arbeitsablauf ist ähnlich dem im vorherigen Anwendungsfall - Sie erzeugen Themenbranches für jede Patchserie, an der Sie arbeiten. Der Unterschied besteht dann darin, wie Sie die Änderungen an das Projekt übermitteln. Anstatt das Projekt zu forken und Änderungen in Ihren Fork hochzuladen, erzeugen Sie E-Mail-Versionen von jeder Ihrer Commit-Folgen und senden diese an die Mailingliste der Entwickler.

The workflow is similar to the previous use case – you create topic branches for each patch series you work on. The difference is how you submit them to the project. Instead of forking the project and pushing to your own writable version, you generate email versions of each commit series and email them to the developer mailing list: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit

<<<<<<< HEAD Jetzt haben Sie zwei Commits, die Sie an die Mailingliste schicken wollen. Sie verwenden die Anweisung git format-patch, um die Dateien im mbox-Format zu erzeugen, die Sie per E-Mail an die Mailingliste schicken können - diese Anweisung macht aus jedem Commit eine E-Mail-Nachricht, wobei die erste Zeile der Commit-Nachricht zum Betreff der E-Mail wird und der Rest der Commit-Nachricht sowie der Patch des Commits selbst wird zum Text der E-Mail. Das Schöne daran ist, dass bei der Anwendung eines Patches von einer mit format-patch erzeugten E-Mail alle Commit-Informationen ordnungsgemäß erhalten bleiben.

Now you have two commits that you want to send to the mailing list. You use git format-patch to generate the mbox-formatted files that you can email to the list – it turns each commit into an email message with the first line of the commit message as the subject and the rest of the message plus the patch that the commit introduces as the body. The nice thing about this is that applying a patch from an email generated with format-patch preserves all the commit information properly. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch

Die Anweisung git format-patch zeigt Ihnen die Namen der Patch-Dateien an, die er erzeugt hat. Die Option -M weist Git an, nach umbenannten Dateien Ausschau zu halten. Die Dateien sehen dann so aus:

$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

---
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log #{treeish}")
+    command("git log -n 20 #{treeish}")
   end

   def ls_tree(treeish = 'master')
--
2.1.0

<<<<<<< HEAD Sie können diese Patch-Dateien auch bearbeiten, um weitere Informationen für die Mailingliste hinzuzufügen, die nicht in der Commit-Nachricht erscheinen sollen. Wenn Sie Text zwischen der --- Zeile und dem Anfang des Patches (der Zeile diff --git) hinzufügen, dann können die Entwickler diesen lesen, bei der Anwendung des Patches wird er aber ausgeschlossen.

Um das jetzt an eine Mailingliste zu schicken, können Sie die Datei entweder in Ihrem E-Mail Programm einfügen oder sie über ein Befehlszeilen-Programm direkt verschicken. Das Einfügen des Textes verursacht oft Formatierungsprobleme – insbesondere mit “smarten” E-Mail-Clients, welche Zeilenumbrüche und Leerzeichen nicht adäquat erhalten. Zum Glück bringt Git aber ein Tool mit, was Ihnen dabei behilflich ist, ordnungsgemäß formatierte Patches über IMAP zu verschicken, was einfacher für Sie sein könnte. Wir werden demonstrieren, wie man Patches über Gmail verschickt, welches der E-Mail-Client ist, mit dem wir uns am besten auskennen; Sie können detaillierte Anleitungen für eine Reihe von E-Mail-Programme am Ende der schon erwähnten Datei Documentation/SubmittingPatches im Git Quellcode nachlesen.

You can also edit these patch files to add more information for the email list that you don’t want to show up in the commit message. If you add text between the --- line and the beginning of the patch (the diff --git line), then developers can read it; but applying the patch excludes it.

To email this to a mailing list, you can either paste the file into your email program or send it via a command-line program. Pasting the text often causes formatting issues, especially with “smarter” clients that don’t preserve newlines and other whitespace appropriately. Luckily, Git provides a tool to help you send properly formatted patches via IMAP, which may be easier for you. We’ll demonstrate how to send a patch via Gmail, which happens to be the email agent we know best; you can read detailed instructions for a number of mail programs at the end of the aforementioned Documentation/SubmittingPatches file in the Git source code. >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

Zunächst müssen Sie den Abschnitt IMAP in Ihrer ~/.gitconfig-Datei einrichten. Sie können jeden Wert separat mit einer Reihe von git config-Anweisungen eingeben oder die Datei öffnen und die Werte manuell eingeben, am Ende sollte Ihre config-Datei in etwa so aussehen:

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com
  user = user@gmail.com
  pass = p4ssw0rd
  port = 993
  sslverify = false

<<<<<<< HEAD Wenn Ihr IMAP-Server kein SSL verwendet, sind die letzten beiden Zeilen wahrscheinlich nicht nötig und der Host-Wert müsste imap:// statt imaps:// lauten. Wenn Sie diese Einstellungen vorgenommen haben, können Sie git send-email verwenden, um die Patches im Entwurfsordner des angegebenen IMAP-Servers zu platzieren:

If your IMAP server doesn’t use SSL, the last two lines probably aren’t necessary, and the host value will be imap:// instead of imaps://. When that is set up, you can use git imap-send to place the patch series in the Drafts folder of the specified IMAP server: >>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done

At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you’re sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off.

You can also send the patches through an SMTP server. As before, you can set each value separately with a series of git config commands, or you can add them manually in the sendemail section in your ~/.gitconfig file:

[sendemail]
  smtpencryption = tls
  smtpserver = smtp.gmail.com
  smtpuser = user@gmail.com
  smtpserverport = 587

After this is done, you can use git send-email to send your patches:

$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y

Git gibt dann für jeden Patch, den Sie versenden, ein paar Log-Informationen aus, die in etwa so aussehen:

(mbox) Adding cc: Jessica Smith <jessica@example.com> from
  \line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>

Result: OK
<<<<<<< HEAD
-----

Jetzt sollten Sie in der Lage sein, zum Entwurfsordner Ihres E-Mail-Clients zu gehen, als Empfänger die Adresse der Mailingliste anzugeben, an die Sie den Patch senden wollen, möglicherweise den Projektbetreiber oder einen anderen Verantwortlichen auf CC zu setzen und die E-Mail dann zu verschicken.
>>>>>>> 811dffebd4ff1348819f8acc70f954bd4ad65057

==== Zusammenfassung

Dieser Abschnitt hat eine Reihe von gebräuchlichen Arbeitsabläufen behandelt, die für jeweils sehr verschiedene Arten von Projekten üblich sind und denen Du vermutlich begegnen wirst. Wir haben außerdem ein paar neue Tools vorgestellt, die dabei hilfreich sind, diese Workflows umzusetzen.
Als nächstes werden wir auf die andere Seite dieser Medaille eingehen: wie Sie selbst ein Git Projekt betreiben können.
Sie werden erfahren, wie Sie als „wohlwollender Diktator“ oder als Integrationsmanager arbeiten können.

=== Maintaining a Project

(((maintaining a project)))
In addition to knowing how to effectively contribute to a project, you'll likely need to know how to maintain one.
This can consist of accepting and applying patches generated via `format-patch` and emailed to you, or integrating changes in remote branches for repositories you've added as remotes to your project.
Whether you maintain a canonical repository or want to help by verifying or approving patches, you need to know how to accept work in a way that is clearest for other contributors and sustainable by you over the long run.

==== Working in Topic Branches

(((branches, topic)))
When you're thinking of integrating new work, it's generally a good idea to try it out in a topic branch – a temporary branch specifically made to try out that new work.
This way, it's easy to tweak a patch individually and leave it if it's not working until you have time to come back to it.
If you create a simple branch name based on the theme of the work you're going to try, such as `ruby_client` or something similarly descriptive, you can easily remember it if you have to abandon it for a while and come back later.
The maintainer of the Git project tends to namespace these branches as well – such as `sc/ruby_client`, where `sc` is short for the person who contributed the work.
As you'll remember, you can create the branch based off your `master` branch like this:

[source,console]

$ git branch sc/ruby_client master

Or, if you want to also switch to it immediately, you can use the `checkout -b` option:

[source,console]

$ git checkout -b sc/ruby_client master

Now you're ready to add the contributed work that you received into this topic branch and determine if you want to merge it into your longer-term branches.

[[_patches_from_email]]
==== Applying Patches from Email

(((email, applying patches from)))
If you receive a patch over email that you need to integrate into your project, you need to apply the patch in your topic branch to evaluate it.
There are two ways to apply an emailed patch: with `git apply` or with `git am`.

===== Applying a Patch with apply

(((git commands, apply)))
If you received the patch from someone who generated it with the `git diff` or a Unix `diff` command (which is not recommended; see the next section), you can apply it with the `git apply` command.
Assuming you saved the patch at `/tmp/patch-ruby-client.patch`, you can apply the patch like this:

[source,console]

$ git apply /tmp/patch-ruby-client.patch

This modifies the files in your working directory.
It's almost identical to running a `patch -p1` command to apply the patch, although it's more paranoid and accepts fewer fuzzy matches than patch.
It also handles file adds, deletes, and renames if they're described in the `git diff` format, which `patch` won't do.
Finally, `git apply` is an ``apply all or abort all'' model where either everything is applied or nothing is, whereas `patch` can partially apply patchfiles, leaving your working directory in a weird state.
`git apply` is overall much more conservative than `patch`.
It won't create a commit for you – after running it, you must stage and commit the changes introduced manually.

You can also use `git apply` to see if a patch applies cleanly before you try actually applying it – you can run `git apply --check` with the patch:

[source,console]

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply

If there is no output, then the patch should apply cleanly.
This command also exits with a non-zero status if the check fails, so you can use it in scripts if you want.

[[_git_am]]
===== Applying a Patch with `am`

(((git commands, am)))
If the contributor is a Git user and was good enough to use the `format-patch` command to generate their patch, then your job is easier because the patch contains author information and a commit message for you.
If you can, encourage your contributors to use `format-patch` instead of `diff` to generate patches for you.
You should only have to use `git apply` for legacy patches and things like that.

To apply a patch generated by `format-patch`, you use `git am` (the command is named `am` as it is used to "apply a series of patches from a mailbox").
Technically, `git am` is built to read an mbox file, which is a simple, plain-text format for storing one or more email messages in one text file.
It looks something like this:

[source,console]

From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001 From: Jessica Smith <jessica@example.com> Date: Sun, 6 Apr 2008 10:17:23 -0700 Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

This is the beginning of the output of the `format-patch` command that you saw in the previous section.
This is also a valid mbox email format.
If someone has emailed you the patch properly using `git send-email`, and you download that into an mbox format, then you can point `git am` to that mbox file, and it will start applying all the patches it sees.
If you run a mail client that can save several emails out in mbox format, you can save entire patch series into a file and then use `git am` to apply them one at a time.

However, if someone uploaded a patch file generated via `format-patch` to a ticketing system or something similar, you can save the file locally and then pass that file saved on your disk to `git am` to apply it:

[source,console]

$ git am 0001-limit-log-function.patch Applying: add limit to log function

You can see that it applied cleanly and automatically created the new commit for you.
The author information is taken from the email's `From` and `Date` headers, and the message of the commit is taken from the `Subject` and body (before the patch) of the email.
For example, if this patch was applied from the mbox example above, the commit generated would look something like this:

[source,console]

$ git log --pretty=fuller -1 commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0 Author: Jessica Smith <jessica@example.com> AuthorDate: Sun Apr 6 10:17:23 2008 -0700 Commit: Scott Chacon <schacon@gmail.com> CommitDate: Thu Apr 9 09:19:06 2009 -0700

add limit to log function
Limit log functionality to the first 20
The `Commit` information indicates the person who applied the patch and the time it was applied.
The `Author` information is the individual who originally created the patch and when it was originally created.

But it's possible that the patch won't apply cleanly.
Perhaps your main branch has diverged too far from the branch the patch was built from, or the patch depends on another patch you haven't applied yet.
In that case, the `git am` process will fail and ask you what you want to do:

[source,console]

$ git am 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply Patch failed at 0001. When you have resolved this problem run "git am --resolved". If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort".

This command puts conflict markers in any files it has issues with, much like a conflicted merge or rebase operation.
You solve this issue much the same way – edit the file to resolve the conflict, stage the new file, and then run `git am --resolved` to continue to the next patch:

[source,console]

$ (fix the file) $ git add ticgit.gemspec $ git am --resolved Applying: seeing if this helps the gem

If you want Git to try a bit more intelligently to resolve the conflict, you can pass a `-3` option to it, which makes Git attempt a three-way merge.
This option isn't on by default because it doesn't work if the commit the patch says it was based on isn't in your repository.
If you do have that commit – if the patch was based on a public commit – then the `-3` option is generally much smarter about applying a conflicting patch:

[source,console]

$ git am -3 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply Using index info to reconstruct a base tree…​ Falling back to patching base and 3-way merge…​ No changes — Patch already applied.

In this case, without the `-3` option the patch would have been considered as a conflict.
Since the `-3` option was used the patch applied cleanly.

If you're applying a number of patches from an mbox, you can also run the `am` command in interactive mode, which stops at each patch it finds and asks if you want to apply it:

[source,console]

$ git am -3 -i mbox Commit Body is:

seeing if this helps the gem

Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

This is nice if you have a number of patches saved, because you can view the patch first if you don't remember what it is, or not apply the patch if you've already done so.

When all the patches for your topic are applied and committed into your branch, you can choose whether and how to integrate them into a longer-running branch.

[[_checking_out_remotes]]
==== Checking Out Remote Branches

(((branches, remote)))
If your contribution came from a Git user who set up their own repository, pushed a number of changes into it, and then sent you the URL to the repository and the name of the remote branch the changes are in, you can add them as a remote and do merges locally.

For instance, if Jessica sends you an email saying that she has a great new feature in the `ruby-client` branch of her repository, you can test it by adding the remote and checking out that branch locally:

[source,console]

$ git remote add jessica git://github.com/jessica/myproject.git $ git fetch jessica $ git checkout -b rubyclient jessica/ruby-client

If she emails you again later with another branch containing another great feature, you could directly `fetch` and `checkout` because you already have the remote setup.

This is most useful if you're working with a person consistently.
If someone only has a single patch to contribute once in a while, then accepting it over email may be less time consuming than requiring everyone to run their own server and having to continually add and remove remotes to get a few patches.
You're also unlikely to want to have hundreds of remotes, each for someone who contributes only a patch or two.
However, scripts and hosted services may make this easier – it depends largely on how you develop and how your contributors develop.

The other advantage of this approach is that you get the history of the commits as well.
Although you may have legitimate merge issues, you know where in your history their work is based; a proper three-way merge is the default rather than having to supply a `-3` and hope the patch was generated off a public commit to which you have access.

If you aren't working with a person consistently but still want to pull from them in this way, you can provide the URL of the remote repository to the `git pull` command.
This does a one-time pull and doesn't save the URL as a remote reference:

[source,console]

$ git pull https://github.com/onetimeguy/project From https://github.com/onetimeguy/project * branch HEAD → FETCH_HEAD Merge made by the recursive strategy.

[[_what_is_introduced]]
==== Determining What Is Introduced

(((branches, diffing)))
Now you have a topic branch that contains contributed work.
At this point, you can determine what you'd like to do with it.
This section revisits a couple of commands so you can see how you can use them to review exactly what you'll be introducing if you merge this into your main branch.

It's often helpful to get a review of all the commits that are in this branch but that aren't in your master branch.
You can exclude commits in the master branch by adding the `--not` option before the branch name.
This does the same thing as the `master..contrib` format that we used earlier.
For example, if your contributor sends you two patches and you create a branch called `contrib` and applied those patches there, you can run this:

[source,console]

$ git log contrib --not master commit 5b6235bd297351589efc4d73316f0a68d484f118 Author: Scott Chacon <schacon@gmail.com> Date: Fri Oct 24 09:53:59 2008 -0700

seeing if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0 Author: Scott Chacon <schacon@gmail.com> Date: Mon Oct 22 19:38:36 2008 -0700

updated the gemspec to hopefully work better
To see what changes each commit introduces, remember that you can pass the `-p` option to `git log` and it will append the diff introduced to each commit.

To see a full diff of what would happen if you were to merge this topic branch with another branch, you may have to use a weird trick to get the correct results.
You may think to run this:

[source,console]

$ git diff master

This command gives you a diff, but it may be misleading.
If your `master` branch has moved forward since you created the topic branch from it, then you'll get seemingly strange results.
This happens because Git directly compares the snapshots of the last commit of the topic branch you're on and the snapshot of the last commit on the `master` branch.
For example, if you've added a line in a file on the `master` branch, a direct comparison of the snapshots will look like the topic branch is going to remove that line.

If `master` is a direct ancestor of your topic branch, this isn't a problem; but if the two histories have diverged, the diff will look like you're adding all the new stuff in your topic branch and removing everything unique to the `master` branch.

What you really want to see are the changes added to the topic branch – the work you'll introduce if you merge this branch with master.
You do that by having Git compare the last commit on your topic branch with the first common ancestor it has with the master branch.

Technically, you can do that by explicitly figuring out the common ancestor and then running your diff on it:

[source,console]

$ git merge-base contrib master 36c7dba2c95e6bbb78dfa822519ecfec6e1ca649 $ git diff 36c7db

However, that isn't convenient, so Git provides another shorthand for doing the same thing: the triple-dot syntax.
In the context of the `diff` command, you can put three periods after another branch to do a `diff` between the last commit of the branch you're on and its common ancestor with another branch:

[source,console]

$ git diff master…​contrib

This command shows you only the work your current topic branch has introduced since its common ancestor with master.
That is a very useful syntax to remember.

==== Integrating Contributed Work

(((integrating work)))
When all the work in your topic branch is ready to be integrated into a more mainline branch, the question is how to do it.
Furthermore, what overall workflow do you want to use to maintain your project?
You have a number of choices, so we'll cover a few of them.

===== Merging Workflows

(((workflows, merging)))
One simple workflow is to merge the work into your `master` branch.
In this scenario, you have a `master` branch that contains basically stable code.
When you have work in a topic branch that you've done or that someone has contributed and you've verified, you merge it into your master branch, delete the topic branch, and then continue the process.
If we have a repository with work in two branches named `ruby_client` and `php_client` that looks like <<merwf_a>> and merge `ruby_client` first and then `php_client` next, then your history will end up looking like <<merwf_b>>.

[[merwf_a]]
.History with several topic branches.
image::images/merging-workflows-1.png[History with several topic branches.]

[[merwf_b]]
.After a topic branch merge.
image::images/merging-workflows-2.png[After a topic branch merge.]

That is probably the simplest workflow, but it can possibly be problematic if you're dealing with larger or more stable projects where you want to be really careful about what you introduce.

If you have a more important project, you might want to use a two-phase merge cycle.
In this scenario, you have two long-running branches, `master` and `develop`, in which you determine that `master` is updated only when a very stable release is cut and all new code is integrated into the `develop` branch.
You regularly push both of these branches to the public repository.
Each time you have a new topic branch to merge in (<<merwf_c>>), you merge it into `develop` (<<merwf_d>>); then, when you tag a release, you fast-forward `master` to wherever the now-stable `develop` branch is (<<merwf_e>>).

[[merwf_c]]
.Before a topic branch merge.
image::images/merging-workflows-3.png[Before a topic branch merge.]

[[merwf_d]]
.After a topic branch merge.
image::images/merging-workflows-4.png[After a topic branch merge.]

[[merwf_e]]
.After a project release.
image::images/merging-workflows-5.png[After a topic branch release.]

This way, when people clone your project's repository, they can either check out `master` to build the latest stable version and keep up to date on that easily, or they can check out `develop`, which is the more cutting-edge stuff.
You can also extend this concept by having an `integrate` branch where all the work is merged together.
Then, when the codebase on that branch is stable and passes tests, you merge it into a `develop` branch; and when that has proven itself stable for a while, you fast-forward your `master` branch.

===== Large-Merging Workflows

(((workflows, "merging (large)")))
The Git project has four long-running branches: `master`, `next`, and `pu` (proposed updates) for new work, and `maint` for maintenance backports.
When new work is introduced by contributors, it's collected into topic branches in the maintainer's repository in a manner similar to what we've described (see <<merwf_f>>).
At this point, the topics are evaluated to determine whether they're safe and ready for consumption or whether they need more work.
If they're safe, they're merged into `next`, and that branch is pushed up so everyone can try the topics integrated together.

[[merwf_f]]
.Managing a complex series of parallel contributed topic branches.
image::images/large-merges-1.png[Managing a complex series of parallel contributed topic branches.]

If the topics still need work, they're merged into `pu` instead.
When it's determined that they're totally stable, the topics are re-merged into `master`.
The `next` and `pu` branches are then rebuilt from the `master`.
This means `master` almost always moves forward, `next` is rebased occasionally, and `pu` is rebased even more often:

.Merging contributed topic branches into long-term integration branches.
image::images/large-merges-2.png[Merging contributed topic branches into long-term integration branches.]

When a topic branch has finally been merged into `master`, it's removed from the repository.
The Git project also has a `maint` branch that is forked off from the last release to provide backported patches in case a maintenance release is required.
Thus, when you clone the Git repository, you have four branches that you can check out to evaluate the project in different stages of development, depending on how cutting edge you want to be or how you want to contribute; and the maintainer has a structured workflow to help them vet new contributions.
The Git project's workflow is specialized. To clearly understand this you could check out the https://github.com/git/git/blob/master/Documentaion/howto/maintain-git.txt[Git Maintainer's guide].

[[_rebase_cherry_pick]]
===== Rebasing and Cherry-Picking Workflows

(((workflows, rebasing and cherry-picking)))
Other maintainers prefer to rebase or cherry-pick contributed work on top of their master branch, rather than merging it in, to keep a mostly linear history.
When you have work in a topic branch and have determined that you want to integrate it, you move to that branch and run the rebase command to rebuild the changes on top of your current master (or `develop`, and so on) branch.
If that works well, you can fast-forward your `master` branch, and you'll end up with a linear project history.

(((git commands, cherry-pick)))
The other way to move introduced work from one branch to another is to cherry-pick it.
A cherry-pick in Git is like a rebase for a single commit.
It takes the patch that was introduced in a commit and tries to reapply it on the branch you're currently on.
This is useful if you have a number of commits on a topic branch and you want to integrate only one of them, or if you only have one commit on a topic branch and you'd prefer to cherry-pick it rather than run rebase.
For example, suppose you have a project that looks like this:

.Example history before a cherry-pick.
image::images/rebasing-1.png[Example history before a cherry-pick.]

If you want to pull commit `e43a6` into your master branch, you can run

[source,console]

$ git cherry-pick e43a6 Finished one cherry-pick. [master]: created a0a41a9: "More friendly message when locking the index fails." 3 files changed, 17 insertions(+), 3 deletions(-)

This pulls the same change introduced in `e43a6`, but you get a new commit SHA-1 value, because the date applied is different.
Now your history looks like this:

.History after cherry-picking a commit on a topic branch.
image::images/rebasing-2.png[History after cherry-picking a commit on a topic branch.]

Now you can remove your topic branch and drop the commits you didn't want to pull in.

===== Rerere

(((git commands, rerere)))(((rerere)))
If you're doing lots of merging and rebasing, or you're maintaining a long-lived topic branch, Git has a feature called ``rerere'' that can help.

Rerere stands for ``reuse recorded resolution'' – it's a way of shortcutting manual conflict resolution.
When rerere is enabled, Git will keep a set of pre- and post-images from successful merges, and if it notices that there's a conflict that looks exactly like one you've already fixed, it'll just use the fix from last time, without bothering you with it.

This feature comes in two parts: a configuration setting and a command.
The configuration setting is `rerere.enabled`, and it's handy enough to put in your global config:

[source,console]

$ git config --global rerere.enabled true

Now, whenever you do a merge that resolves conflicts, the resolution will be recorded in the cache in case you need it in the future.

If you need to, you can interact with the rerere cache using the `git rerere` command.
When it's invoked alone, Git checks its database of resolutions and tries to find a match with any current merge conflicts and resolve them (although this is done automatically if `rerere.enabled` is set to `true`).
There are also subcommands to see what will be recorded, to erase specific resolution from the cache, and to clear the entire cache.
We will cover rerere in more detail in <<_rerere>>.

[[_tagging_releases]]
==== Tagging Your Releases

(((tags)))(((tags, signing)))
When you've decided to cut a release, you'll probably want to drop a tag so you can re-create that release at any point going forward.
You can create a new tag as discussed in <<_git_basics_chapter>>.
If you decide to sign the tag as the maintainer, the tagging may look something like this:

[source,console]

$ git tag -s v1.5 -m my signed 1.5 tag You need a passphrase to unlock the secret key for user: "Scott Chacon <schacon@gmail.com>" 1024-bit DSA key, ID F721C45A, created 2009-02-09

If you do sign your tags, you may have the problem of distributing the public PGP key used to sign your tags.
The maintainer of the Git project has solved this issue by including their public key as a blob in the repository and then adding a tag that points directly to that content.
To do this, you can figure out which key you want by running `gpg --list-keys`:

[source,console]

$ gpg --list-keys /Users/schacon/.gnupg/pubring.gpg

pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]
----

Then, you can directly import the key into the Git database by exporting it and piping that through `git hash-object`, which writes a new blob with those contents into Git and gives you back the SHA-1 of the blob:

[source,console]
----
$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92
----

Now that you have the contents of your key in Git, you can create a tag that points directly to it by specifying the new SHA-1 value that the `hash-object` command gave you:

[source,console]
----
$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92
----

If you run `git push --tags`, the `maintainer-pgp-pub` tag will be shared with everyone.
If anyone wants to verify a tag, they can directly import your PGP key by pulling the blob directly out of the database and importing it into GPG:

[source,console]
----
$ git show maintainer-pgp-pub | gpg --import
----

They can use that key to verify all your signed tags.
Also, if you include instructions in the tag message, running `git show <tag>` will let you give the end user more specific instructions about tag verification.

[[_build_number]]
==== Generating a Build Number

(((build numbers)))(((git commands, describe)))
Because Git doesn't have monotonically increasing numbers like 'v123' or the equivalent to go with each commit, if you want to have a human-readable name to go with a commit, you can run `git describe` on that commit.
Git gives you the name of the nearest tag with the number of commits on top of that tag and a partial SHA-1 value of the commit you're describing:

[source,console]
----
$ git describe master
v1.6.2-rc1-20-g8c5b85c
----

This way, you can export a snapshot or build and name it something understandable to people.
In fact, if you build Git from source code cloned from the Git repository, `git --version` gives you something that looks like this.
If you're describing a commit that you have directly tagged, it gives you the tag name.

The `git describe` command favors annotated tags (tags created with the `-a` or `-s` flag), so release tags should be created this way if you're using `git describe`, to ensure the commit is named properly when described.
You can also use this string as the target of a checkout or show command, although it relies on the abbreviated SHA-1 value at the end, so it may not be valid forever.
For instance, the Linux kernel recently jumped from 8 to 10 characters to ensure SHA-1 object uniqueness, so older `git describe` output names were invalidated.

[[_preparing_release]]
==== Preparing a Release

(((releasing)))(((git commands, archive)))
Now you want to release a build.
One of the things you'll want to do is create an archive of the latest snapshot of your code for those poor souls who don't use Git.
The command to do this is `git archive`:

[source,console]
----
$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz
----

If someone opens that tarball, they get the latest snapshot of your project under a project directory.
You can also create a zip archive in much the same way, but by passing the `--format=zip` option to `git archive`:

[source,console]
----
$ git archive master --prefix='project/' --format=zip > `git describe master`.zip
----

You now have a nice tarball and a zip archive of your project release that you can upload to your website or email to people.

[[_the_shortlog]]
==== The Shortlog

(((git commands, shortlog)))
It's time to email your mailing list of people who want to know what's happening in your project.
A nice way of quickly getting a sort of changelog of what has been added to your project since your last release or email is to use the `git shortlog` command.
It summarizes all the commits in the range you give it; for example, the following gives you a summary of all the commits since your last release, if your last release was named v1.0.1:

[source,console]
----
$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (8):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2
----

You get a clean summary of all the commits since v1.0.1, grouped by author, that you can email to your list.


=== Zusammenfassung

Sie sollten einigermaßen vertraut damit sein, an einem Projekt in Git mitzuarbeiten, Ihre eigenen Projekte zu pflegen oder die Beiträge anderer Entwickler zu integrieren.
Glückwunsch, jetzt sind Sie ein erfolgreicher Git-Entwickler.
Im nächsten Kapitel werden Sie erfahren, wie Sie den größten und bekanntesten Git-Hosting-Dienst, GitHub, benutzen können.


[[_github]]
== GitHub

(((GitHub)))
GitHub is the single largest host for Git repositories, and is the central point of collaboration for millions of developers and projects.
A large percentage of all Git repositories are hosted on GitHub, and many open-source projects use it for Git hosting, issue tracking, code review, and other things.
So while it's not a direct part of the Git open source project, there's a good chance that you'll want or need to interact with GitHub at some point while using Git professionally.

This chapter is about using GitHub effectively.
We'll cover signing up for and managing an account, creating and using Git repositories, common workflows to contribute to projects and to accept contributions to yours, GitHub's programmatic interface and lots of little tips to make your life easier in general.

If you are not interested in using GitHub to host your own projects or to collaborate with other projects that are hosted on GitHub, you can safely skip to <<_git_tools>>.

[WARNING]
.Interfaces Change
====
It's important to note that like many active websites, the UI elements in these screenshots are bound to change over time.
Hopefully the general idea of what we're trying to accomplish here will still be there, but if you want more up to date versions of these screens, the online versions of this book may have newer screenshots.
====

=== Account Setup and Configuration

(((GitHub, user accounts)))
The first thing you need to do is set up a free user account.
Simply visit https://github.com[], choose a user name that isn't already taken, provide an email address and a password, and click the big green ``Sign up for GitHub'' button.

.The GitHub sign-up form.
image::images/signup.png[The GitHub sign-up form.]

The next thing you'll see is the pricing page for upgraded plans, but it's safe to ignore this for now.
GitHub will send you an email to verify the address you provided.
Go ahead and do this, it's pretty important (as we'll see later).

[NOTE]
====
GitHub provides all of its functionality with free accounts, with the limitation that all of your projects are fully public (everyone has read access).
GitHub's paid plans include a set number of private projects, but we won't be covering those in this book.
====

Clicking the Octocat logo at the top-left of the screen will take you to your dashboard page.
You're now ready to use GitHub.

==== SSH Access

(((SSH keys, with GitHub)))
As of right now, you're fully able to connect with Git repositories using the `https://` protocol, authenticating with the username and password you just set up.
However, to simply clone public projects, you don't even need to sign up - the account we just created comes into play when we fork projects and push to our forks a bit later.

If you'd like to use SSH remotes, you'll need to configure a public key.
(If you don't already have one, see <<_generate_ssh_key>>.)
Open up your account settings using the link at the top-right of the window:

.The ``Account settings'' link.
image::images/account-settings.png[The ``Account settings'' link.]

Then select the ``SSH keys'' section along the left-hand side.

.The ``SSH keys'' link.
image::images/ssh-keys.png[The ``SSH keys'' link.]

From there, click the "`Add an SSH key`" button, give your key a name, paste the contents of your `~/.ssh/id_rsa.pub` (or whatever you named it) public-key file into the text area, and click ``Add key''.

[NOTE]
====
Be sure to name your SSH key something you can remember.
You can name each of your keys (e.g. "My Laptop" or "Work Account") so that if you need to revoke a key later, you can easily tell which one you're looking for.
====

[[_personal_avatar]]
==== Your Avatar

Next, if you wish, you can replace the avatar that is generated for you with an image of your choosing.
First go to the ``Profile'' tab (above the SSH Keys tab) and click ``Upload new picture''.

.The ``Profile'' link.
image::images/your-profile.png[The ``Profile'' link.]

We'll choose a copy of the Git logo that is on our hard drive and then we get a chance to crop it.

.Crop your avatar
image::images/avatar-crop.png[Crop your uploaded avatar.]

Now anywhere you interact on the site, people will see your avatar next to your username.

If you happen to have uploaded an avatar to the popular Gravatar service (often used for Wordpress accounts), that avatar will be used by default and you don't need to do this step.

==== Your Email Addresses

The way that GitHub maps your Git commits to your user is by email address.
If you use multiple email addresses in your commits and you want GitHub to link them up properly, you need to add all the email addresses you have used to the Emails section of the admin section.

[[_add_email_addresses]]
.Add email addresses
image::images/email-settings.png[Add all your email addresses.]

In <<_add_email_addresses>> we can see some of the different states that are possible.
The top address is verified and set as the primary address, meaning that is where you'll get any notifications and receipts.
The second address is verified and so can be set as the primary if you wish to switch them.
The final address is unverified, meaning that you can't make it your primary address.
If GitHub sees any of these in commit messages in any repository on the site, it will be linked to your user now.

==== Two Factor Authentication

Finally, for extra security, you should definitely set up Two-factor Authentication or ``2FA''.
Two-factor Authentication is an authentication mechanism that is becoming more and more popular recently to mitigate the risk of your account being compromised if your password is stolen somehow.
Turning it on will make GitHub ask you for two different methods of authentication, so that if one of them is compromised, an attacker will not be able to access your account.

You can find the Two-factor Authentication setup under the Security tab of your Account settings.

.2FA in the Security Tab
image::images/2fa-1.png[2FA in the Security Tab]

If you click on the ``Set up two-factor authentication'' button, it will take you to a configuration page where you can choose to use a phone app to generate your secondary code (a ``time based one-time password''), or you can have GitHub send you a code via SMS each time you need to log in.

After you choose which method you prefer and follow the instructions for setting up 2FA, your account will then be a little more secure and you will have to provide a code in addition to your password whenever you log into GitHub.


=== Contributing to a Project

Now that our account is set up, let's walk through some details that could be useful in helping you contribute to an existing project.

==== Forking Projects

(((forking)))
If you want to contribute to an existing project to which you don’t have push access, you can ``fork'' the project.
When you ``fork'' a project, GitHub will make a copy of the project that is entirely yours; it lives in your namespace, and you can push to it.

[NOTE]
====
Historically, the term ``fork'' has been somewhat negative in context, meaning that someone took an open source project in a different direction, sometimes creating a competing project and splitting the contributors.
In GitHub, a ``fork'' is simply the same project in your own namespace, allowing you to make changes to a project publicly as a way to contribute in a more open manner.
====

This way, projects don’t have to worry about adding users as collaborators to give them push access.
People can fork a project, push to it, and contribute their changes back to the original repository by creating what's called a Pull Request, which we'll cover next.
This opens up a discussion thread with code review, and the owner and the contributor can then communicate about the change until the owner is happy with it, at which point the owner can merge it in.

To fork a project, visit the project page and click the ``Fork'' button at the top-right of the page.

.The ``Fork'' button.
image::images/forkbutton.png[The ``Fork'' button.]

After a few seconds, you'll be taken to your new project page, with your own writeable copy of the code.


[[_github_flow]]
==== The GitHub Flow

(((GitHub, Flow)))
GitHub is designed around a particular collaboration workflow, centered on Pull Requests.
This flow works whether you're collaborating with a tightly-knit team in a single shared repository, or a globally-distributed company or network of strangers contributing to a project through dozens of forks.
It is centered on the <<_topic_branch>> workflow covered in <<_git_branching>>.

Here's how it generally works:

1. Fork the project
2. Create a topic branch from `master`.
3. Make some commits to improve the project.
4. Push this branch to your GitHub project.
5. Open a Pull Request on GitHub.
6. Discuss, and optionally continue committing.
7. The project owner merges or closes the Pull Request.

This is basically the Integration Manager workflow covered in <<_integration_manager>>, but instead of using email to communicate and review changes, teams use GitHub's web based tools.

Let's walk through an example of proposing a change to an open source project hosted on GitHub using this flow.

===== Creating a Pull Request

Tony is looking for code to run on his Arduino programmable microcontroller and has found a great program file on GitHub at https://github.com/schacon/blink[].

.The project we want to contribute to.
image::images/blink-01-start.png[The project we want to contribute to.]

The only problem is that the blinking rate is too fast, we think it's much nicer to wait 3 seconds instead of 1 in between each state change.
So let's improve the program and submit it back to the project as a proposed change.

First, we click the 'Fork' button as mentioned earlier to get our own copy of the project.
Our user name here is ``tonychacon'' so our copy of this project is at `https://github.com/tonychacon/blink` and that's where we can edit it.
We will clone it locally, create a topic branch, make the code change and finally push that change back up to GitHub.

[source,console]
----
$ git clone https://github.com/tonychacon/blink (1)
Cloning into 'blink'...

$ cd blink
$ git checkout -b slow-blink (2)
Switched to a new branch 'slow-blink'

$ sed -i '' 's/1000/3000/' blink.ino (3)

$ git diff --word-diff (4)
diff --git a/blink.ino b/blink.ino
index 15b9911..a6cc5a5 100644
--- a/blink.ino
+++ b/blink.ino
@@ -18,7 +18,7 @@ void setup() {
// the loop routine runs over and over again forever:
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  [-delay(1000);-]{+delay(3000);+}               // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  [-delay(1000);-]{+delay(3000);+}               // wait for a second
}

$ git commit -a -m 'three seconds is better' (5)
[slow-blink 5ca509d] three seconds is better
 1 file changed, 2 insertions(+), 2 deletions(-)

$ git push origin slow-blink (6)
Username for 'https://github.com': tonychacon
Password for 'https://tonychacon@github.com':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 340 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To https://github.com/tonychacon/blink
 * [new branch]      slow-blink -> slow-blink
----

<1> Clone our fork of the project locally
<2> Create a descriptive topic branch
<3> Make our change to the code
<4> Check that the change is good
<5> Commit our change to the topic branch
<6> Push our new topic branch back up to our GitHub fork

Now if we go back to our fork on GitHub, we can see that GitHub noticed that we pushed a new topic branch up and present us with a big green button to check out our changes and open a Pull Request to the original project.

You can alternatively go to the ``Branches'' page at `https://github.com/<user>/<project>/branches` to locate your branch and open a new Pull Request from there.

.Pull Request button
image::images/blink-02-pr.png[Pull Request button]

(((GitHub, pull requests)))
If we click that green button, we'll see a screen that asks us to give our Pull Request a title and description.
It is almost always worthwhile to put some effort into this, since a good description helps the owner of the original project determine what you were trying to do, whether your proposed changes are correct, and whether accepting the changes would improve the original project.

We also see a list of the commits in our topic branch that are ``ahead'' of the `master` branch (in this case, just the one) and a unified diff of all the changes that will be made should this branch get merged by the project owner.

.Pull Request creation page
image::images/blink-03-pull-request-open.png[Pull Request creation]

When you hit the 'Create pull request' button on this screen, the owner of the project you forked will get a notification that someone is suggesting a change and will link to a page that has all of this information on it.

[NOTE]
====
Though Pull Requests are used commonly for public projects like this when the contributor has a complete change ready to be made, it's also often used in internal projects _at the beginning_ of the development cycle. Since you can keep pushing to the topic branch even *after* the Pull Request is opened, it's often opened early and used as a way to iterate on work as a team within a context, rather than opened at the very end of the process.
====

===== Iterating on a Pull Request

At this point, the project owner can look at the suggested change and merge it, reject it or comment on it. Let's say that he likes the idea, but would prefer a slightly longer time for the light to be off than on.

Where this conversation may take place over email in the workflows presented in <<_distributed_git>>, on GitHub this happens online. The project owner can review the unified diff and leave a comment by clicking on any of the lines.

.Comment on a specific line of code in a Pull Request
image::images/blink-04-pr-comment.png[PR line comment]

Once the maintainer makes this comment, the person who opened the Pull Request (and indeed, anyone else watching the repository) will get a notification. We'll go over customizing this later, but if he had email notifications turned on, Tony would get an email like this:

[[_email_notification]]
.Comments sent as email notifications
image::images/blink-04-email.png[Email notification]

Anyone can also leave general comments on the Pull Request. In <<_pr_discussion>> we can see an example of the project owner both commenting on a line of code and then leaving a general comment in the discussion section. You can see that the code comments are brought into the conversation as well.

[[_pr_discussion]]
.Pull Request discussion page
image::images/blink-05-general-comment.png[PR discussion page]

Now the contributor can see what they need to do in order to get their change accepted.
Luckily this is very straightforward.
Where over email you may have to re-roll your series and resubmit it to the mailing list, with GitHub you simply commit to the topic branch again and push, which will automatically update the Pull Request.
In <<_pr_final>> you can also see that the old code comment has been collapsed in the updated Pull Request, since it was made on a line that has since been changed.

Adding commits to an existing Pull Request doesn't trigger a notification, so once Tony has pushed his corrections he decides to leave a comment to inform the project owner that he made the requested change.

[[_pr_final]]
.Pull Request final
image::images/blink-06-final.png[PR final]

An interesting thing to notice is that if you click on the ``Files Changed'' tab on this Pull Request, you'll get the ``unified'' diff -- that is, the total aggregate difference that would be introduced to your main branch if this topic branch was merged in. In `git diff` terms, it basically automatically shows you `git diff master...<branch>` for the branch this Pull Request is based on. See <<_what_is_introduced>> for more about this type of diff.

The other thing you'll notice is that GitHub checks to see if the Pull Request merges cleanly and provides a button to do the merge for you on the server. This button only shows up if you have write access to the repository and a trivial merge is possible. If you click it GitHub will perform a ``non-fast-forward'' merge, meaning that even if the merge *could* be a fast-forward, it will still create a merge commit.

If you would prefer, you can simply pull the branch down and merge it locally. If you merge this branch into the `master` branch and push it to GitHub, the Pull Request will automatically be closed.

This is the basic workflow that most GitHub projects use. Topic branches are created, Pull Requests are opened on them, a discussion ensues, possibly more work is done on the branch and eventually the request is either closed or merged.

[NOTE]
.Not Only Forks
====
It's important to note that you can also open a Pull Request between two branches in the same repository. If you're working on a feature with someone and you both have write access to the project, you can push a topic branch to the repository and open a Pull Request on it to the `master` branch of that same project to initiate the code review and discussion process. No forking necessary.
====

==== Advanced Pull Requests

Now that we've covered the basics of contributing to a project on GitHub, let's cover a few interesting tips and tricks about Pull Requests so you can be more effective in using them.

===== Pull Requests as Patches

It's important to understand that many projects don't really think of Pull Requests as queues of perfect patches that should apply cleanly in order, as most mailing list-based projects think of patch series contributions. Most GitHub projects think about Pull Request branches as iterative conversations around a proposed change, culminating in a unified diff that is applied by merging.

This is an important distinction, because generally the change is suggested before the code is thought to be perfect, which is far more rare with mailing list based patch series contributions. This enables an earlier conversation with the maintainers so that arriving at the proper solution is more of a community effort. When code is proposed with a Pull Request and the maintainers or community suggest a change, the patch series is generally not re-rolled, but instead the difference is pushed as a new commit to the branch, moving the conversation forward with the context of the previous work intact.

For instance, if you go back and look again at <<_pr_final>>, you'll notice that the contributor did not rebase his commit and send another Pull Request. Instead they added new commits and pushed them to the existing branch. This way if you go back and look at this Pull Request in the future, you can easily find all of the context of why decisions were made. Pushing the ``Merge'' button on the site purposefully creates a merge commit that references the Pull Request so that it's easy to go back and research the original conversation if necessary.

===== Keeping up with Upstream

If your Pull Request becomes out of date or otherwise doesn't merge cleanly, you will want to fix it so the maintainer can easily merge it. GitHub will test this for you and let you know at the bottom of every Pull Request if the merge is trivial or not.

[[_pr_fail]]
.Pull Request does not merge cleanly
image::images/pr-01-fail.png[PR merge failure]

If you see something like <<_pr_fail>>, you'll want to fix your branch so that it turns green and the maintainer doesn't have to do extra work.

You have two main options in order to do this. You can either rebase your branch on top of whatever the target branch is (normally the `master` branch of the repository you forked), or you can merge the target branch into your branch.

Most developers on GitHub will choose to do the latter, for the same reasons we just went over in the previous section. What matters is the history and the final merge, so rebasing isn't getting you much other than a slightly cleaner history and in return is *far* more difficult and error prone.

If you want to merge in the target branch to make your Pull Request mergeable, you would add the original repository as a new remote, fetch from it, merge the main branch of that repository into your topic branch, fix any issues and finally push it back up to the same branch you opened the Pull Request on.

For example, let's say that in the ``tonychacon'' example we were using before, the original author made a change that would create a conflict in the Pull Request. Let's go through those steps.

[source,console]
----
$ git remote add upstream https://github.com/schacon/blink (1)

$ git fetch upstream (2)
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (3/3), done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From https://github.com/schacon/blink
 * [new branch]      master     -> upstream/master

$ git merge upstream/master (3)
Auto-merging blink.ino
CONFLICT (content): Merge conflict in blink.ino
Automatic merge failed; fix conflicts and then commit the result.

$ vim blink.ino (4)
$ git add blink.ino
$ git commit
[slow-blink 3c8d735] Merge remote-tracking branch 'upstream/master' \
    into slower-blink

$ git push origin slow-blink (5)
Counting objects: 6, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (6/6), 682 bytes | 0 bytes/s, done.
Total 6 (delta 2), reused 0 (delta 0)
To https://github.com/tonychacon/blink
   ef4725c..3c8d735  slower-blink -> slow-blink
----

<1> Add the original repository as a remote named ``upstream''
<2> Fetch the newest work from that remote
<3> Merge the main branch into your topic branch
<4> Fix the conflict that occurred
<5> Push back up to the same topic branch

Once you do that, the Pull Request will be automatically updated and re-checked to see if it merges cleanly.

[[_pr_merge_fix]]
.Pull Request now merges cleanly
image::images/pr-02-merge-fix.png[PR fixed]

One of the great things about Git is that you can do that continuously. If you have a very long-running project, you can easily merge from the target branch over and over again and only have to deal with conflicts that have arisen since the last time that you merged, making the process very manageable.

If you absolutely wish to rebase the branch to clean it up, you can certainly do so, but it is highly encouraged to not force push over the branch that the Pull Request is already opened on. If other people have pulled it down and done more work on it, you run into all of the issues outlined in <<_rebase_peril>>. Instead, push the rebased branch to a new branch on GitHub and open a brand new Pull Request referencing the old one, then close the original.

===== References

Your next question may be ``How do I reference the old Pull Request?''. It turns out there are many, many ways to reference other things almost anywhere you can write in GitHub.

Let's start with how to cross-reference another Pull Request or an Issue. All Pull Requests and Issues are assigned numbers and they are unique within the project. For example, you can't have Pull Request #3 _and_ Issue #3. If you want to reference any Pull Request or Issue from any other one, you can simply put `#<num>` in any comment or description. You can also be more specific if the Issue or Pull request lives somewhere else; write `username#<num>` if you're referring to an Issue or Pull Request in a fork of the repository you're in, or `username/repo#<num>` to reference something in another repository.

Let's look at an example. Say we rebased the branch in the previous example, created a new pull request for it, and now we want to reference the old pull request from the new one. We also want to reference an issue in the fork of the repository and an issue in a completely different project. We can fill out the description just like <<_pr_references>>.

[[_pr_references]]
.Cross references in a Pull Request.
image::images/mentions-01-syntax.png[PR references]

When we submit this pull request, we'll see all of that rendered like <<_pr_references_render>>.

[[_pr_references_render]]
.Cross references rendered in a Pull Request.
image::images/mentions-02-render.png[PR references rendered]

Notice that the full GitHub URL we put in there was shortened to just the information needed.

Now if Tony goes back and closes out the original Pull Request, we can see that by mentioning it in the new one, GitHub has automatically created a trackback event in the Pull Request timeline. This means that anyone who visits this Pull Request and sees that it is closed can easily link back to the one that superseded it. The link will look something like <<_pr_closed>>.

[[_pr_closed]]
.Cross references rendered in a Pull Request.
image::images/mentions-03-closed.png[PR closed]

In addition to issue numbers, you can also reference a specific commit by SHA-1. You have to specify a full 40 character SHA-1, but if GitHub sees that in a comment, it will link directly to the commit. Again, you can reference commits in forks or other repositories in the same way you did with issues.

==== GitHub Flavored Markdown

Linking to other Issues is just the beginning of interesting things you can do with almost any text box on GitHub. In  Issue and Pull Request descriptions, comments, code comments and more, you can use what is called ``GitHub Flavored Markdown''. Markdown is like writing in plain text but which is rendered richly.

See <<_example_markdown>> for an example of how comments or text can be written and then rendered using Markdown.

[[_example_markdown]]
.An example of GitHub Flavored Markdown as written and as rendered.
image::images/markdown-01-example.png[Example Markdown]

The GitHub flavor of Markdown adds more things you can do beyond the basic Markdown syntax. These can all be really useful when creating useful Pull Request or Issue comments or descriptions.

===== Task Lists

The first really useful GitHub specific Markdown feature, especially for use in Pull Requests, is the Task List. A task list is a list of checkboxes of things you want to get done. Putting them into an Issue or Pull Request normally indicates things that you want to get done before you consider the item complete.

You can create a task list like this:

[source,text]
----
- [X] Write the code
- [ ] Write all the tests
- [ ] Document the code
----

If we include this in the description of our Pull Request or Issue, we'll see it rendered like <<_task_lists>>

[[_task_lists]]
.Task lists rendered in a Markdown comment.
image::images/markdown-02-tasks.png[Example Task List]

This is often used in Pull Requests to indicate what all you would like to get done on the branch before the Pull Request will be ready to merge. The really cool part is that you can simply click the checkboxes to update the comment -- you don't have to edit the Markdown directly to check tasks off.

What's more, GitHub will look for task lists in your Issues and Pull Requests and show them as metadata on the pages that list them out. For example, if you have a Pull Request with tasks and you look at the overview page of all Pull Requests, you can see how far done it is. This helps people break down Pull Requests into subtasks and helps other people track the progress of the branch. You can see an example of this in <<_task_list_progress>>.

[[_task_list_progress]]
.Task list summary in the Pull Request list.
image::images/markdown-03-task-summary.png[Example Task List]

These are incredibly useful when you open a Pull Request early and use it to track your progress through the implementation of the feature.

===== Code Snippets

You can also add code snippets to comments. This is especially useful if you want to present something that you _could_ try to do before actually implementing it as a commit on your branch. This is also often used to add example code of what is not working or what this Pull Request could implement.

To add a snippet of code you have to ``fence'' it in backticks.

[source,text]
----
```java
for(int i=0 ; i < 5 ; i++)
{
   System.out.println("i is : " + i);
}
```
----

If you add a language name like we did there with 'java', GitHub will also try to syntax highlight the snippet. In the case of the above example, it would end up rendering like <<_md_code>>.

[[_md_code]]
.Rendered fenced code example.
image::images/markdown-04-fenced-code.png[Rendered fenced code]

===== Quoting

If you're responding to a small part of a long comment, you can selectively quote out of the other comment by preceding the lines with the `>` character. In fact, this is so common and so useful that there is a keyboard shortcut for it. If you highlight text in a comment that you want to directly reply to and hit the `r` key, it will quote that text in the comment box for you.

The quotes look something like this:

[source,text]
----
> Whether 'tis Nobler in the mind to suffer
> The Slings and Arrows of outrageous Fortune,

How big are these slings and in particular, these arrows?
----

Once rendered, the comment will look like <<_md_quote>>.

[[_md_quote]]
.Rendered quoting example.
image::images/markdown-05-quote.png[Rendered quoting]

===== Emoji

Finally, you can also use emoji in your comments. This is actually used quite extensively in comments you see on many GitHub Issues and Pull Requests. There is even an emoji helper in GitHub. If you are typing a comment and you start with a `:` character, an autocompleter will help you find what you're looking for.

[[_md_emoji_auto]]
.Emoji autocompleter in action.
image::images/markdown-06-emoji-complete.png[Emoji autocompleter]

Emojis take the form of `:<name>:` anywhere in the comment. For instance, you could write something like this:

[source,text]
----
I :eyes: that :bug: and I :cold_sweat:.

:trophy: for :microscope: it.

:+1: and :sparkles: on this :ship:, it's :fire::poop:!

:clap::tada::panda_face:
----

When rendered, it would look something like <<_md_emoji>>.

[[_md_emoji]]
.Heavy emoji commenting.
image::images/markdown-07-emoji.png[Emoji]

Not that this is incredibly useful, but it does add an element of fun and emotion to a medium that is otherwise hard to convey emotion in.


[NOTE]
====
There are actually quite a number of web services that make use of emoji characters these days. A great cheat sheet to reference to find emoji that expresses what you want to say can be found at:

http://www.emoji-cheat-sheet.com
====

===== Images

This isn't technically GitHub Flavored Markdown, but it is incredibly useful. In addition to adding Markdown image links to comments, which can be difficult to find and embed URLs for, GitHub allows you to drag and drop images into text areas to embed them.

[[_md_drag]]
.Drag and drop images to upload them and auto-embed them.
image::images/markdown-08-drag-drop.png[Drag and drop images]

If you look at <<_md_drag>>, you can see a small ``Parsed as Markdown'' hint above the text area. Clicking on that will give you a full cheat sheet of everything you can do with Markdown on GitHub.


[[_maintaining_gh_project]]
=== Maintaining a Project

Now that we're comfortable contributing to a project, let's look at the other side: creating, maintaining and administering your own project.

==== Creating a New Repository

Let's create a new repository to share our project code with.
Start by clicking the ``New repository'' button on the right-hand side of the dashboard, or from the `+` button in the top toolbar next to your username as seen in <<_new_repo_dropdown>>.

.The ``Your repositories'' area.
image::images/newrepo.png[The ``Your repositories'' area.]

[[_new_repo_dropdown]]
.The ``New repository'' dropdown.
image::images/new-repo.png[The ``new repository'' dropdown.]

This takes you to the ``new repository'' form:

.The ``new repository'' form.
image::images/newrepoform.png[The ``new repository'' form.]

All you really have to do here is provide a project name; the rest of the fields are completely optional.
For now, just click the ``Create Repository'' button, and boom – you have a new repository on GitHub, named `<user>/<project_name>`.

Since you have no code there yet, GitHub will show you instructions for how to create a brand-new Git repository, or connect an existing Git project.
We won't belabor this here; if you need a refresher, check out <<_git_basics_chapter>>.

Now that your project is hosted on GitHub, you can give the URL to anyone you want to share your project with.
Every project on GitHub is accessible over HTTPS as `https://github.com/<user>/<project_name>`, and over SSH as `git@github.com:<user>/<project_name>`.
Git can fetch from and push to both of these URLs, but they are access-controlled based on the credentials of the user connecting to them.

[NOTE]
====
It is often preferable to share the HTTPS based URL for a public project, since the user does not have to have a GitHub account to access it for cloning.
Users will have to have an account and an uploaded SSH key to access your project if you give them the SSH URL.
The HTTPS one is also exactly the same URL they would paste into a browser to view the project there.
====

==== Adding Collaborators

If you're working with other people who you want to give commit access to, you need to add them as ``collaborators''.
If Ben, Jeff, and Louise all sign up for accounts on GitHub, and you want to give them push access to your repository, you can add them to your project.
Doing so will give them ``push'' access, which means they have both read and write access to the project and Git repository.

Click the ``Settings'' link at the bottom of the right-hand sidebar.

.The repository settings link.
image::images/reposettingslink.png[The repository settings link.]

Then select ``Collaborators'' from the menu on the left-hand side.
Then, just type a username into the box, and click ``Add collaborator.''
You can repeat this as many times as you like to grant access to everyone you like.
If you need to revoke access, just click the ``X'' on the right-hand side of their row.

.Repository collaborators.
image::images/collaborators.png[The repository collaborators box.]

==== Managing Pull Requests

Now that you have a project with some code in it and maybe even a few collaborators who also have push access, let's go over what to do when you get a Pull Request yourself.

Pull Requests can either come from a branch in a fork of your repository or they can come from another branch in the same repository.
The only difference is that the ones in a fork are often from people where you can't push to their branch and they can't push to yours, whereas with internal Pull Requests generally both parties can access the branch.

For these examples, let's assume you are ``tonychacon'' and you've created a new Arduino code project named ``fade''.

[[_email_notifications]]
===== Email Notifications

Someone comes along and makes a change to your code and sends you a Pull Request.
You should get an email notifying you about the new Pull Request and it should look something like <<_email_pr>>.

[[_email_pr]]
.Email notification of a new Pull Request.
image::images/maint-01-email.png[Pull Request email notification]

There are a few things to notice about this email.
It will give you a small diffstat -- a list of files that have changed in the Pull Request and by how much.
It gives you a link to the Pull Request on GitHub.
It also gives you a few URLs that you can use from the command line.

If you notice the line that says `git pull <url> patch-1`, this is a simple way to merge in a remote branch without having to add a remote.
We went over this quickly in <<_checking_out_remotes>>.
If you wish, you can create and switch to a topic branch and then run this command to merge in the Pull Request changes.

The other interesting URLs are the `.diff` and `.patch` URLs, which as you may guess, provide unified diff and patch versions of the Pull Request.
You could technically merge in the Pull Request work with something like this:

[source,console]
----
$ curl http://github.com/tonychacon/fade/pull/1.patch | git am
----

===== Collaborating on the Pull Request

As we covered in <<_github_flow>>, you can now have a conversation with the person who opened the Pull Request.
You can comment on specific lines of code, comment on whole commits or comment on the entire Pull Request itself, using GitHub Flavored Markdown everywhere.

Every time someone else comments on the Pull Request you will continue to get email notifications so you know there is activity happening.
They will each have a link to the Pull Request where the activity is happening and you can also directly respond to the email to comment on the Pull Request thread.

.Responses to emails are included in the thread.
image::images/maint-03-email-resp.png[Email response]

Once the code is in a place you like and want to merge it in, you can either pull the code down and merge it locally, either with the `git pull <url> <branch>` syntax we saw earlier, or by adding the fork as a remote and fetching and merging.

If the merge is trivial, you can also just hit the ``Merge'' button on the GitHub site.
This will do a ``non-fast-forward'' merge, creating a merge commit even if a fast-forward merge was possible.
This means that no matter what, every time you hit the merge button, a merge commit is created.
As you can see in <<_merge_button>>, GitHub gives you all of this information if you click the hint link.

[[_merge_button]]
.Merge button and instructions for merging a Pull Request manually.
image::images/maint-02-merge.png[Merge button]

If you decide you don't want to merge it, you can also just close the Pull Request and the person who opened it will be notified.

[[_pr_refs]]
===== Pull Request Refs

If you're dealing with a *lot* of Pull Requests and don't want to add a bunch of remotes or do one time pulls every time, there is a neat trick that GitHub allows you to do.
This is a bit of an advanced trick and we'll go over the details of this a bit more in <<_refspec>>, but it can be pretty useful.

GitHub actually advertises the Pull Request branches for a repository as sort of pseudo-branches on the server.
By default you don't get them when you clone, but they are there in an obscured way and you can access them pretty easily.

To demonstrate this, we're going to use a low-level command (often referred to as a ``plumbing'' command, which we'll read about more in <<_plumbing_porcelain>>) called `ls-remote`.
This command is generally not used in day-to-day Git operations but it's useful to show us what references are present on the server.

If we run this command against the ``blink'' repository we were using earlier, we will get a list of all the branches and tags and other references in the repository.

[source,console]
----
$ git ls-remote https://github.com/schacon/blink
10d539600d86723087810ec636870a504f4fee4d	HEAD
10d539600d86723087810ec636870a504f4fee4d	refs/heads/master
6a83107c62950be9453aac297bb0193fd743cd6e	refs/pull/1/head
afe83c2d1a70674c9505cc1d8b7d380d5e076ed3	refs/pull/1/merge
3c8d735ee16296c242be7a9742ebfbc2665adec1	refs/pull/2/head
15c9f4f80973a2758462ab2066b6ad9fe8dcf03d	refs/pull/2/merge
a5a7751a33b7e86c5e9bb07b26001bb17d775d1a	refs/pull/4/head
31a45fc257e8433c8d8804e3e848cf61c9d3166c	refs/pull/4/merge
----

Of course, if you're in your repository and you run `git ls-remote origin` or whatever remote you want to check, it will show you something similar to this.

If the repository is on GitHub and you have any Pull Requests that have been opened, you'll get these references that are prefixed with `refs/pull/`.
These are basically branches, but since they're not under `refs/heads/` you don't get them normally when you clone or fetch from the server -- the process of fetching ignores them normally.

There are two references per Pull Request - the one that ends in `/head` points to exactly the same commit as the last commit in the Pull Request branch.
So if someone opens a Pull Request in our repository and their branch is named `bug-fix` and it points to commit `a5a775`, then in *our* repository we will not have a `bug-fix` branch (since that's in their fork), but we _will_ have `pull/<pr#>/head` that points to `a5a775`.
This means that we can pretty easily pull down every Pull Request branch in one go without having to add a bunch of remotes.

Now, you could do something like fetching the reference directly.

[source,console]
----
$ git fetch origin refs/pull/958/head
From https://github.com/libgit2/libgit2
 * branch            refs/pull/958/head -> FETCH_HEAD
----

This tells Git, ``Connect to the `origin` remote, and download the ref named `refs/pull/958/head`.''
Git happily obeys, and downloads everything you need to construct that ref, and puts a pointer to the commit you want under `.git/FETCH_HEAD`.
You can follow that up with `git merge FETCH_HEAD` into a branch you want to test it in, but that merge commit message looks a bit weird.
Also, if you're reviewing a *lot* of pull requests, this gets tedious.

There's also a way to fetch _all_ of the pull requests, and keep them up to date whenever you connect to the remote.
Open up `.git/config` in your favorite editor, and look for the `origin` remote.
It should look a bit like this:

[source,ini]
----
[remote "origin"]
    url = https://github.com/libgit2/libgit2
    fetch = +refs/heads/*:refs/remotes/origin/*
----

That line that begins with `fetch =` is a ``refspec.''
It's a way of mapping names on the remote with names in your local `.git` directory.
This particular one tells Git, "the things on the remote that are under `refs/heads` should go in my local repository under `refs/remotes/origin`."
You can modify this section to add another refspec:

[source,ini]
----
[remote "origin"]
    url = https://github.com/libgit2/libgit2.git
    fetch = +refs/heads/*:refs/remotes/origin/*
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*
----

That last line tells Git, ``All the refs that look like `refs/pull/123/head` should be stored locally like `refs/remotes/origin/pr/123`.''
Now, if you save that file, and do a `git fetch`:

[source,console]
----
$ git fetch
# …
 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
 * [new ref]         refs/pull/4/head -> origin/pr/4
# …
----

Now all of the remote pull requests are represented locally with refs that act much like tracking branches; they're read-only, and they update when you do a fetch.
This makes it super easy to try the code from a pull request locally:

[source,console]
----
$ git checkout pr/2
Checking out files: 100% (3769/3769), done.
Branch pr/2 set up to track remote branch pr/2 from origin.
Switched to a new branch 'pr/2'
----

The eagle-eyed among you would note the `head` on the end of the remote portion of the refspec.
There's also a `refs/pull/#/merge` ref on the GitHub side, which represents the commit that would result if you push the ``merge'' button on the site.
This can allow you to test the merge before even hitting the button.


===== Pull Requests on Pull Requests

Not only can you open Pull Requests that target the main or `master` branch, you can actually open a Pull Request targeting any branch in the network.
In fact, you can even target another Pull Request.

If you see a Pull Request that is moving in the right direction and you have an idea for a change that depends on it or you're not sure is a good idea, or you just don't have push access to the target branch, you can open a Pull Request directly to it.

When you go to open a Pull Request, there is a box at the top of the page that specifies which branch you're requesting to pull to and which you're requesting to pull from.
If you hit the ``Edit'' button at the right of that box you can change not only the branches but also which fork.

[[_pr_targets]]
.Manually change the Pull Request target fork and branch.
image::images/maint-04-target.png[PR targets]

Here you can fairly easily specify to merge your new branch into another Pull Request or another fork of the project.

==== Mentions and Notifications

GitHub also has a pretty nice notifications system built in that can come in handy when you have questions or need feedback from specific individuals or teams.

In any comment you can start typing a `@` character and it will begin to autocomplete with the names and usernames of people who are collaborators or contributors in the project.

.Start typing @ to mention someone.
image::images/maint-05-mentions.png[Mentions]

You can also mention a user who is not in that dropdown, but often the autocompleter can make it faster.

Once you post a comment with a user mention, that user will be notified.
This means that this can be a really effective way of pulling people into conversations rather than making them poll.
Very often in  Pull Requests on GitHub people will pull in other people on their teams or in their company to review an Issue or Pull Request.

If someone gets mentioned on a Pull Request or Issue, they will be ``subscribed'' to it and will continue getting notifications any time some activity occurs on it.
You will also be subscribed to something if you opened it, if you're watching the repository or if you comment on something.
If you no longer wish to receive notifications, there is an ``Unsubscribe'' button on the page you can click to stop receiving updates on it.

.Unsubscribe from an Issue or Pull Request.
image::images/maint-06-unsubscribe.png[Unsubscribe]

===== The Notifications Page

When we mention ``notifications'' here with respect to GitHub, we mean a specific way that GitHub tries to get in touch with you when events happen and there are a few different ways you can configure them.
If you go to the ``Notification center'' tab from the settings page, you can see some of the options you have.

.Notification center options.
image::images/maint-07-notifications.png[Notification center]

The two choices are to get notifications over ``Email'' and over ``Web'' and you can choose either, neither or both for when you actively participate in things and for activity on repositories you are watching.

====== Web Notifications

Web notifications only exist on GitHub and you can only check them on GitHub.
If you have this option selected in your preferences and a notification is triggered for you, you will see a small blue dot over your notifications icon at the top of your screen as seen in <<_not_center>>.

[[_not_center]]
.Notification center.
image::images/maint-08-notifications-page.png[Notification center]

If you click on that, you will see a list of all the items you have been notified about, grouped by project.
You can filter to the notifications of a specific project by clicking on its name in the left hand sidebar.
You can also acknowledge the notification by clicking the checkmark icon next to any notification, or acknowledge _all_ of the notifications in a project by clicking the checkmark at the top of the group.
There is also a mute button next to each checkmark that you can click to not receive any further notifications on that item.

All of these tools are very useful for handling large numbers of notifications.
Many GitHub power users will simply turn off email notifications entirely and manage all of their notifications through this screen.

====== Email Notifications

Email notifications are the other way you can handle notifications through GitHub.
If you have this turned on you will get emails for each notification.
We saw examples of this in <<_email_notification>> and <<_email_pr>>.
The emails will also be threaded properly, which is nice if you're using a threading email client.

There is also a fair amount of metadata embedded in the headers of the emails that GitHub sends you, which can be really helpful for setting up custom filters and rules.

For instance, if we look at the actual email headers sent to Tony in the email shown in <<_email_pr>>, we will see the following among the information sent:

[source,mbox]
----
To: tonychacon/fade <fade@noreply.github.com>
Message-ID: <tonychacon/fade/pull/1@github.com>
Subject: [fade] Wait longer to see the dimming effect better (#1)
X-GitHub-Recipient: tonychacon
List-ID: tonychacon/fade <fade.tonychacon.github.com>
List-Archive: https://github.com/tonychacon/fade
List-Post: <mailto:reply+i-4XXX@reply.github.com>
List-Unsubscribe: <mailto:unsub+i-XXX@reply.github.com>,...
X-GitHub-Recipient-Address: tchacon@example.com
----

There are a couple of interesting things here.
If you want to highlight or re-route emails to this particular project or even Pull Request, the information in `Message-ID` gives you all the data in `<user>/<project>/<type>/<id>` format.
If this were an issue, for example, the `<type>` field would have been ``issues'' rather than ``pull''.

The `List-Post` and `List-Unsubscribe` fields mean that if you have a mail client that understands those, you can easily post to the list or ``Unsubscribe'' from the thread.
That would be essentially the same as clicking the ``mute'' button on the web version of the notification or ``Unsubscribe'' on the Issue or Pull Request page itself.

It's also worth noting that if you have both email and web notifications enabled and you read the email version of the notification, the web version will be marked as read as well if you have images allowed in your mail client.

==== Special Files

There are a couple of special files that GitHub will notice if they are present in your repository.

==== README

The first is the `README` file, which can be of nearly any format that GitHub recognizes as prose.
For example, it could be `README`, `README.md`, `README.asciidoc`, etc.
If GitHub sees a README file in your source, it will render it on the landing page of the project.

Many teams use this file to hold all the relevant project information for someone who might be new to the repository or project.
This generally includes things like:

* What the project is for
* How to configure and install it
* An example of how to use it or get it running
* The license that the project is offered under
* How to contribute to it

Since GitHub will render this file, you can embed images or links in it for added ease of understanding.

==== CONTRIBUTING

The other special file that GitHub recognizes is the `CONTRIBUTING` file.
If you have a file named `CONTRIBUTING` with any file extension, GitHub will show <<_contrib_file>> when anyone starts opening a Pull Request.

[[_contrib_file]]
.Opening a Pull Request when a CONTRIBUTING file exists.
image::images/maint-09-contrib.png[Contributing notice]

The idea here is that you can specify specific things you want or don't want in a Pull Request sent to your project.
This way people may actually read the guidelines before opening the Pull Request.

==== Project Administration

Generally there are not a lot of administrative things you can do with a single project, but there are a couple of items that might be of interest.

===== Changing the Default Branch

If you are using a branch other than ``master'' as your default branch that you want people to open Pull Requests on or see by default, you can change that in your repository's settings page under the ``Options'' tab.

[[_default_branch]]
.Change the default branch for a project.
image::images/maint-10-default-branch.png[Default branch]

Simply change the default branch in the dropdown and that will be the default for all major operations from then on, including which branch is checked out by default when someone clones the repository.

===== Transferring a Project

If you would like to transfer a project to another user or an organization in GitHub, there is a ``Transfer ownership'' option at the bottom of the same ``Options'' tab of your repository settings page that allows you to do this.

[[_transfer_project]]
.Transfer a project to another GitHub user or Organization.
image::images/maint-11-transfer.png[Transfer]

This is helpful if you are abandoning a project and someone wants to take it over, or if your project is getting bigger and want to move it into an organization.

Not only does this move the repository along with all its watchers and stars to another place, it also sets up a redirect from your URL to the new place.
It will also redirect clones and fetches from Git, not just web requests.


[[_github_orgs]]
=== Managing an organization

(((GitHub, organizations)))
In addition to single-user accounts, GitHub has what are called Organizations.
Like personal accounts, Organizational accounts have a namespace where all their projects exist, but many other things are different.
These accounts represent a group of people with shared ownership of projects, and there are many tools to manage subgroups of those people.
Normally these accounts are used for Open Source groups (such as ``perl'' or ``rails'') or companies (such as ``google'' or ``twitter'').

==== Organization Basics

An organization is pretty easy to create; just click on the ``+'' icon at the top-right of any GitHub page, and select ``New organization'' from the menu.

.The ``New organization'' menu item.
image::images/neworg.png[The ``New organization'' menu item.]

First you'll need to name your organization and provide an email address for a main point of contact for the group.
Then you can invite other users to be co-owners of the account if you want to.

Follow these steps and you'll soon be the owner of a brand-new organization.
Like personal accounts, organizations are free if everything you plan to store there will be open source.

As an owner in an organization, when you fork a repository, you'll have the choice of forking it to your organization's namespace.
When you create new repositories you can create them either under your personal account or under any of the organizations that you are an owner in.
You also automatically ``watch'' any new repository created under these organizations.

Just like in <<_personal_avatar>>, you can upload an avatar for your organization to personalize it a bit.
Also just like personal accounts, you have a landing page for the organization that lists all of your repositories and can be viewed by other people.

Now let's cover some of the things that are a bit different with an organizational account.

==== Teams

Organizations are associated with individual people by way of teams, which are simply a grouping of individual user accounts and repositories within the organization and what kind of access those people have in those repositories.

For example, say your company has three repositories: `frontend`, `backend`, and `deployscripts`.
You'd want your HTML/CSS/JavaScript developers to have access to `frontend` and maybe `backend`, and your Operations people to have access to `backend` and `deployscripts`.
Teams make this easy, without having to manage the collaborators for every individual repository.

The Organization page shows you a simple dashboard of all the repositories, users and teams that are under this organization.

[[_org_page]]
.The Organization page.
image::images/orgs-01-page.png[]

To manage your Teams, you can click on the Teams sidebar on the right hand side of the page in <<_org_page>>.
This will bring you to a page you can use to add members to the team, add repositories to the team or manage the settings and access control levels for the team.
Each team can have read only, read/write or administrative access to the repositories.
You can change that level by clicking the ``Settings'' button in <<_team_page>>.

[[_team_page]]
.The Team page.
image::images/orgs-02-teams.png[]

When you invite someone to a team, they will get an email letting them know they've been invited.

Additionally, team `@mentions` (such as `@acmecorp/frontend`) work much the same as they do with individual users, except that *all* members of the team are then subscribed to the thread.
This is useful if you want the attention from someone on a team, but you don't know exactly who to ask.

A user can belong to any number of teams, so don't limit yourself to only access-control teams.
Special-interest teams like `ux`, `css`, or `refactoring` are useful for certain kinds of questions, and others like `legal` and `colorblind` for an entirely different kind.

==== Audit Log

Organizations also give owners access to all the information about what went on under the organization.
You can go to the 'Audit Log' tab and see what events have happened at an organization level, who did them and where in the world they were done.

[[_audit_log]]
.The Audit log.
image::images/orgs-03-audit.png[]

You can also filter down to specific types of events, specific places or specific people.


=== Scripting GitHub

So now we've covered all of the major features and workflows of GitHub, but any large group or project will have customizations they may want to make or external services they may want to integrate.

Luckily for us, GitHub is really quite hackable in many ways.
In this section we'll cover how to use the GitHub hooks system and its API to make GitHub work how we want it to.

==== Services and Hooks

The Hooks and Services section of GitHub repository administration is the easiest way to have GitHub interact with external systems.

===== Services

First we'll take a look at Services.
Both the Hooks and Services integrations can be found in the Settings section of your repository, where we previously looked at adding Collaborators and changing the default branch of your project.
Under the ``Webhooks and Services'' tab you will see something like <<_services_hooks>>.

[[_services_hooks]]
.Services and Hooks configuration section.
image::images/scripting-01-services.png[Services and hooks]

There are dozens of services you can choose from, most of them integrations into other commercial and open source systems.
Most of them are for Continuous Integration services, bug and issue trackers, chat room systems and documentation systems.
We'll walk through setting up a very simple one, the Email hook.
If you choose ``email'' from the ``Add Service'' dropdown, you'll get a configuration screen like <<_service_config>>.

[[_service_config]]
.Email service configuration.
image::images/scripting-02-email-service.png[Email service]

In this case, if we hit the ``Add service'' button, the email address we specified will get an email every time someone pushes to the repository.
Services can listen for lots of different types of events, but most only listen for push events and then do something with that data.

If there is a system you are using that you would like to integrate with GitHub, you should check here to see if there is an existing service integration available.
For example, if you're using Jenkins to run tests on your codebase, you can enable the Jenkins builtin service integration to kick off a test run every time someone pushes to your repository.

===== Hooks

If you need something more specific or you want to integrate with a service or site that is not included in this list, you can instead use the more generic hooks system.
GitHub repository hooks are pretty simple.
You specify a URL and GitHub will post an HTTP payload to that URL on any event you want.

Generally the way this works is you can setup a small web service to listen for a GitHub hook payload and then do something with the data when it is received.

To enable a hook, you click the ``Add webhook'' button in <<_services_hooks>>.
This will bring you to a page that looks like <<_web_hook>>.

[[_web_hook]]
.Web hook configuration.
image::images/scripting-03-webhook.png[Web hook]

The configuration for a web hook is pretty simple.
In most cases you simply enter a URL and a secret key and hit ``Add webhook''.
There are a few options for which events you want GitHub to send you a payload for -- the default is to only get a payload for the `push` event, when someone pushes new code to any branch of your repository.

Let's see a small example of a web service you may set up to handle a web hook.
We'll use the Ruby web framework Sinatra since it's fairly concise and you should be able to easily see what we're doing.

Let's say we want to get an email if a specific person pushes to a specific branch of our project modifying a specific file.
We could fairly easily do that with code like this:

[source,ruby]
----
require 'sinatra'
require 'json'
require 'mail'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON

  # gather the data we're looking for
  pusher = push["pusher"]["name"]
  branch = push["ref"]

  # get a list of all the files touched
  files = push["commits"].map do |commit|
    commit['added'] + commit['modified'] + commit['removed']
  end
  files = files.flatten.uniq

  # check for our criteria
  if pusher == 'schacon' &&
     branch == 'ref/heads/special-branch' &&
     files.include?('special-file.txt')

    Mail.deliver do
      from     'tchacon@example.com'
      to       'tchacon@example.com'
      subject  'Scott Changed the File'
      body     "ALARM"
    end
  end
end
----

Here we're taking the JSON payload that GitHub delivers us and looking up who pushed it, what branch they pushed to and what files were touched in all the commits that were pushed.
Then we check that against our criteria and send an email if it matches.

In order to develop and test something like this, you have a nice developer console in the same screen where you set the hook up.
You can see the last few deliveries that GitHub has tried to make for that webhook.
For each hook you can dig down into when it was delivered, if it was successful and the body and headers for both the request and the response.
This makes it incredibly easy to test and debug your hooks.

[[_web_hook_debug]]
.Web hook debugging information.
image::images/scripting-04-webhook-debug.png[Webhook debug]

The other great feature of this is that you can redeliver any of the payloads to test your service easily.

For more information on how to write webhooks and all the different event types you can listen for, go to the GitHub Developer documentation at https://developer.github.com/webhooks/

==== The GitHub API

(((GitHub, API)))
Services and hooks give you a way to receive push notifications about events that happen on your repositories, but what if you need more information about these events?
What if you need to automate something like adding collaborators or labeling issues?

This is where the GitHub API comes in handy.
GitHub has tons of API endpoints for doing nearly anything you can do on the website in an automated fashion.
In this section we'll learn how to authenticate and connect to the API, how to comment on an issue and how to change the status of a Pull Request through the API.

==== Basic Usage

The most basic thing you can do is a simple GET request on an endpoint that doesn't require authentication.
This could be a user or read-only information on an open source project.
For example, if we want to know more about a user named ``schacon'', we can run something like this:

[source,javascript]
----
$ curl https://api.github.com/users/schacon
{
  "login": "schacon",
  "id": 70,
  "avatar_url": "https://avatars.githubusercontent.com/u/70",
# …
  "name": "Scott Chacon",
  "company": "GitHub",
  "following": 19,
  "created_at": "2008-01-27T17:19:28Z",
  "updated_at": "2014-06-10T02:37:23Z"
}
----

There are tons of endpoints like this to get information about organizations, projects, issues, commits -- just about anything you can publicly see on GitHub.
You can even use the API to render arbitrary Markdown or find a `.gitignore` template.

[source,javascript]
----
$ curl https://api.github.com/gitignore/templates/Java
{
  "name": "Java",
  "source": "*.class

# Mobile Tools for Java (J2ME)
.mtj.tmp/

# Package Files #
*.jar
*.war
*.ear

# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
"
}
----


==== Commenting on an Issue

However, if you want to do an action on the website such as comment on an Issue or Pull Request or if you want to view or interact with private content, you'll need to authenticate.

There are several ways to authenticate.
You can use basic authentication with just your username and password, but generally it's a better idea to use a personal access token.
You can generate this from the ``Applications'' tab of your settings page.

[[_access_token]]
.Generate your access token from the ``Applications'' tab of your settings page.
image::images/scripting-05-access-token.png[Access Token]

It will ask you which scopes you want for this token and a description.
Make sure to use a good description so you feel comfortable removing the token when your script or application is no longer used.

GitHub will only show you the token once, so be sure to copy it.
You can now use this to authenticate in your script instead of using a username and password.
This is nice because you can limit the scope of what you want to do and the token is revocable.

This also has the added advantage of increasing your rate limit.
Without authenticating, you will be limited to 60 requests per hour.
If you authenticate you can make up to 5,000 requests per hour.

So let's use it to make a comment on one of our issues.
Let's say we want to leave a comment on a specific issue, Issue #6.
To do so we have to do an HTTP POST request to `repos/<user>/<repo>/issues/<num>/comments` with the token we just generated as an Authorization header.

[source,javascript]
----
$ curl -H "Content-Type: application/json" \
       -H "Authorization: token TOKEN" \
       --data '{"body":"A new comment, :+1:"}' \
       https://api.github.com/repos/schacon/blink/issues/6/comments
{
  "id": 58322100,
  "html_url": "https://github.com/schacon/blink/issues/6#issuecomment-58322100",
  ...
  "user": {
    "login": "tonychacon",
    "id": 7874698,
    "avatar_url": "https://avatars.githubusercontent.com/u/7874698?v=2",
    "type": "User",
  },
  "created_at": "2014-10-08T07:48:19Z",
  "updated_at": "2014-10-08T07:48:19Z",
  "body": "A new comment, :+1:"
}
----

Now if you go to that issue, you can see the comment that we just successfully posted as in <<_api_comment>>.

[[_api_comment]]
.A comment posted from the GitHub API.
image::images/scripting-06-comment.png[API Comment]

You can use the API to do just about anything you can do on the website -- creating and setting milestones, assigning people to Issues and Pull Requests, creating and changing labels, accessing commit data, creating new commits and branches, opening, closing or merging Pull Requests, creating and editing teams, commenting on lines of code in a Pull Request, searching the site and on and on.

==== Changing the Status of a Pull Request

There is one final example we'll look at since it's really useful if you're working with Pull Requests.
Each commit can have one or more statuses associated with it and there is an API to add and query that status.

Most of the Continuous Integration and testing services make use of this API to react to pushes by testing the code that was pushed, and then report back if that commit has passed all the tests.
You could also use this to check if the commit message is properly formatted, if the submitter followed all your contribution guidelines, if the commit was validly signed -- any number of things.

Let's say you set up a webhook on your repository that hits a small web service that checks for a `Signed-off-by` string in the commit message.

[source,ruby]
----
require 'httparty'
require 'sinatra'
require 'json'

post '/payload' do
  push = JSON.parse(request.body.read) # parse the JSON
  repo_name = push['repository']['full_name']

  # look through each commit message
  push["commits"].each do |commit|

    # look for a Signed-off-by string
    if /Signed-off-by/.match commit['message']
      state = 'success'
      description = 'Successfully signed off!'
    else
      state = 'failure'
      description = 'No signoff found.'
    end

    # post status to GitHub
    sha = commit["id"]
    status_url = "https://api.github.com/repos/#{repo_name}/statuses/#{sha}"

    status = {
      "state"       => state,
      "description" => description,
      "target_url"  => "http://example.com/how-to-signoff",
      "context"     => "validate/signoff"
    }
    HTTParty.post(status_url,
      :body => status.to_json,
      :headers => {
        'Content-Type'  => 'application/json',
        'User-Agent'    => 'tonychacon/signoff',
        'Authorization' => "token #{ENV['TOKEN']}" }
    )
  end
end
----

Hopefully this is fairly simple to follow.
In this web hook handler we look through each commit that was just pushed, we look for the string 'Signed-off-by' in the commit message and finally we POST via HTTP to the `/repos/<user>/<repo>/statuses/<commit_sha>` API endpoint with the status.

In this case you can send a state ('success', 'failure', 'error'), a description of what happened, a target URL the user can go to for more information and a ``context'' in case there are multiple statuses for a single commit.
For example, a testing service may provide a status and a validation service like this may also provide a status -- the ``context'' field is how they're differentiated.

If someone opens a new Pull Request on GitHub and this hook is set up, you may see something like <<_commit_status>>.

[[_commit_status]]
.Commit status via the API.
image::images/scripting-07-status.png[Commit status]

You can now see a little green check mark next to the commit that has a ``Signed-off-by'' string in the message and a red cross through the one where the author forgot to sign off.
You can also see that the Pull Request takes the status of the last commit on the branch and warns you if it is a failure.
This is really useful if you're using this API for test results so you don't accidentally merge something where the last commit is failing tests.

==== Octokit

Though we've been doing nearly everything through `curl` and simple HTTP requests in these examples, several open-source libraries exist that make this API available in a more idiomatic way.
At the time of this writing, the supported languages include Go, Objective-C, Ruby, and .NET.
Check out http://github.com/octokit[] for more information on these, as they handle much of the HTTP for you.

Hopefully these tools can help you customize and modify GitHub to work better for your specific workflows.
For complete documentation on the entire API as well as guides for common tasks, check out https://developer.github.com[].


=== Summary

Now you're a GitHub user.
You know how to create an account, manage an organization, create and push to repositories, contribute to other people's projects and accept contributions from others.
In the next chapter, you'll learn more powerful tools and tips for dealing with complex situations, which will truly make you a Git master.


[[_git_tools]]
== Git Tools

By now, you’ve learned most of the day-to-day commands and workflows that you need to manage or maintain a Git repository for your source code control.
You’ve accomplished the basic tasks of tracking and committing files, and you’ve harnessed the power of the staging area and lightweight topic branching and merging.

Now you’ll explore a number of very powerful things that Git can do that you may not necessarily use on a day-to-day basis but that you may need at some point.

[[_revision_selection]]
=== Revision Selection

Git allows you to specify specific commits or a range of commits in several ways.
They aren’t necessarily obvious but are helpful to know.

==== Single Revisions

You can obviously refer to a commit by the SHA-1 hash that it’s given, but there are more human-friendly ways to refer to commits as well.
This section outlines the various ways you can refer to a single commit.

==== Short SHA-1

Git is smart enough to figure out what commit you meant to type if you provide the first few characters, as long as your partial SHA-1 is at least four characters long and unambiguous – that is, only one object in the current repository begins with that partial SHA-1.

For example, to see a specific commit, suppose you run a `git log` command and identify the commit where you added certain functionality:

[source,console]
----
$ git log
commit 734713bc047d87bf7eac9674765ae793478c50d3
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    fixed refs handling, added gc auto, updated tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'

commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    added some blame and merge stuff
----

In this case, choose `1c002dd...`. If you `git show` that commit, the following commands are equivalent (assuming the shorter versions are unambiguous):

[source,console]
----
$ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b
$ git show 1c002dd4b536e7479f
$ git show 1c002d
----

Git can figure out a short, unique abbreviation for your SHA-1 values.
If you pass `--abbrev-commit` to the `git log` command, the output will use shorter values but keep them unique; it defaults to using seven characters but makes them longer if necessary to keep the SHA-1 unambiguous:

[source,console]
----
$ git log --abbrev-commit --pretty=oneline
ca82a6d changed the version number
085bb3b removed unnecessary test code
a11bef0 first commit
----

Generally, eight to ten characters are more than enough to be unique within a project.

As an example, the Linux kernel, which is a pretty large project with over 450k commits and 3.6 million objects, has no two objects whose SHA-1s overlap more than the first 11 characters.

[NOTE]
.A SHORT NOTE ABOUT SHA-1
====

A lot of people become concerned at some point that they will, by random happenstance, have two objects in their repository that hash to the same SHA-1 value.
What then?

If you do happen to commit an object that hashes to the same SHA-1 value as a previous object in your repository, Git will see the previous object already in your Git database and assume it was already written.
If you try to check out that object again at some point, you’ll always get the data of the first object.

However, you should be aware of how ridiculously unlikely this scenario is.
The SHA-1 digest is 20 bytes or 160 bits.
The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80^
(the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160))`. 2^80^
is 1.2 x 10^24^
or 1 million billion billion.
That’s 1,200 times the number of grains of sand on the earth.

Here’s an example to give you an idea of what it would take to get a SHA-1 collision.
If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (3.6 million Git objects) and pushing it into one enormous Git repository, it would take roughly 2 years until that repository contained enough objects to have a 50% probability of a single SHA-1 object collision.
A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night.
====

[[_branch_references]]
==== Branch References

The most straightforward way to specify a commit requires that it has a branch reference pointed at it.
Then, you can use a branch name in any Git command that expects a commit object or SHA-1 value.
For instance, if you want to show the last commit object on a branch, the following commands are equivalent, assuming that the `topic1` branch points to `ca82a6d`:

[source,console]
----
$ git show ca82a6dff817ec66f44342007202690a93763949
$ git show topic1
----

If you want to see which specific SHA-1 a branch points to, or if you want to see what any of these examples boils down to in terms of SHA-1s, you can use a Git plumbing tool called `rev-parse`.
You can see <<_git_internals>> for more information about plumbing tools; basically, `rev-parse` exists for lower-level operations and isn’t designed to be used in day-to-day operations.
However, it can be helpful sometimes when you need to see what’s really going on.
Here you can run `rev-parse` on your branch.

[source,console]
----
$ git rev-parse topic1
ca82a6dff817ec66f44342007202690a93763949
----

[[_git_reflog]]
==== RefLog Shortnames

One of the things Git does in the background while you’re working away is keep a ``reflog'' – a log of where your HEAD and branch references have been for the last few months.

You can see your reflog by using `git reflog`:

[source,console]
----
$ git reflog
734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated
d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive.
1c002dd HEAD@{2}: commit: added some blame and merge stuff
1c36188 HEAD@{3}: rebase -i (squash): updating HEAD
95df984 HEAD@{4}: commit: # This is a combination of two commits.
1c36188 HEAD@{5}: rebase -i (squash): updating HEAD
7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD
----

Every time your branch tip is updated for any reason, Git stores that information for you in this temporary history.
And you can specify older commits with this data, as well.
If you want to see the fifth prior value of the HEAD of your repository, you can use the `@{n}` reference that you see in the reflog output:

[source,console]
----
$ git show HEAD@{5}
----

You can also use this syntax to see where a branch was some specific amount of time ago.
For instance, to see where your `master` branch was yesterday, you can type

[source,console]
----
$ git show master@{yesterday}
----

That shows you where the branch tip was yesterday.
This technique only works for data that’s still in your reflog, so you can’t use it to look for commits older than a few months.

To see reflog information formatted like the `git log` output, you can run `git log -g`:

[source,console]
----
$ git log -g master
commit 734713bc047d87bf7eac9674765ae793478c50d3
Reflog: master@{0} (Scott Chacon <schacon@gmail.com>)
Reflog message: commit: fixed refs handling, added gc auto, updated
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Jan 2 18:32:33 2009 -0800

    fixed refs handling, added gc auto, updated tests

commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Reflog: master@{1} (Scott Chacon <schacon@gmail.com>)
Reflog message: merge phedders/rdocs: Merge made by recursive.
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'
----

It’s important to note that the reflog information is strictly local – it’s a log of what you’ve done in your repository.
The references won’t be the same on someone else’s copy of the repository; and right after you initially clone a repository, you'll have an empty reflog, as no activity has occurred yet in your repository.
Running `git show HEAD@{2.months.ago}` will work only if you cloned the project at least two months ago – if you cloned it five minutes ago, you’ll get no results.

==== Ancestry References

The other main way to specify a commit is via its ancestry.
If you place a `^` at the end of a reference, Git resolves it to mean the parent of that commit.
Suppose you look at the history of your project:

[source,console]
----
$ git log --pretty=format:'%h %s' --graph
* 734713b fixed refs handling, added gc auto, updated tests
*   d921970 Merge commit 'phedders/rdocs'
|\
| * 35cfb2b Some rdoc changes
* | 1c002dd added some blame and merge stuff
|/
* 1c36188 ignore *.gem
* 9b29157 add open3_detach to gemspec file list
----

Then, you can see the previous commit by specifying `HEAD^`, which means ``the parent of HEAD'':

[source,console]
----
$ git show HEAD^
commit d921970aadf03b3cf0e71becdaab3147ba71cdef
Merge: 1c002dd... 35cfb2b...
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 15:08:43 2008 -0800

    Merge commit 'phedders/rdocs'
----

You can also specify a number after the `^` – for example, `d921970^2` means ``the second parent of d921970.''
This syntax is only useful for merge commits, which have more than one parent.
The first parent is the branch you were on when you merged, and the second is the commit on the branch that you merged in:

[source,console]
----
$ git show d921970^
commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b
Author: Scott Chacon <schacon@gmail.com>
Date:   Thu Dec 11 14:58:32 2008 -0800

    added some blame and merge stuff

$ git show d921970^2
commit 35cfb2b795a55793d7cc56a6cc2060b4bb732548
Author: Paul Hedderly <paul+git@mjr.org>
Date:   Wed Dec 10 22:22:03 2008 +0000

    Some rdoc changes
----

The other main ancestry specification is the `~`.
This also refers to the first parent, so `HEAD~` and `HEAD^` are equivalent.
The difference becomes apparent when you specify a number.
`HEAD~2` means ``the first parent of the first parent,'' or ``the grandparent'' – it traverses the first parents the number of times you specify.
For example, in the history listed earlier, `HEAD~3` would be

[source,console]
----
$ git show HEAD~3
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    ignore *.gem
----

This can also be written `HEAD^^^`, which again is the first parent of the first parent of the first parent:

[source,console]
----
$ git show HEAD^^^
commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d
Author: Tom Preston-Werner <tom@mojombo.com>
Date:   Fri Nov 7 13:47:59 2008 -0500

    ignore *.gem
----

You can also combine these syntaxes – you can get the second parent of the previous reference (assuming it was a merge commit) by using `HEAD~3^2`, and so on.

[[_commit_ranges]]
==== Commit Ranges

Now that you can specify individual commits, let’s see how to specify ranges of commits.
This is particularly useful for managing your branches – if you have a lot of branches, you can use range specifications to answer questions such as, ``What work is on this branch that I haven’t yet merged into my main branch?''

===== Double Dot

The most common range specification is the double-dot syntax.
This basically asks Git to resolve a range of commits that are reachable from one commit but aren’t reachable from another.
For example, say you have a commit history that looks like <<double_dot>>.

[[double_dot]]
.Example history for range selection.
image::images/double-dot.png[Example history for range selection.]

You want to see what is in your experiment branch that hasn’t yet been merged into your master branch.
You can ask Git to show you a log of just those commits with `master..experiment` – that means ``all commits reachable by experiment that aren’t reachable by master.''
For the sake of brevity and clarity in these examples, I’ll use the letters of the commit objects from the diagram in place of the actual log output in the order that they would display:

[source,console]
----
$ git log master..experiment
D
C
----

If, on the other hand, you want to see the opposite – all commits in `master` that aren’t in `experiment` – you can reverse the branch names.
`experiment..master` shows you everything in `master` not reachable from `experiment`:

[source,console]
----
$ git log experiment..master
F
E
----

This is useful if you want to keep the `experiment` branch up to date and preview what you’re about to merge in.
Another very frequent use of this syntax is to see what you’re about to push to a remote:

[source,console]
----
$ git log origin/master..HEAD
----

This command shows you any commits in your current branch that aren’t in the `master` branch on your `origin` remote.
If you run a `git push` and your current branch is tracking `origin/master`, the commits listed by `git log origin/master..HEAD` are the commits that will be transferred to the server.
You can also leave off one side of the syntax to have Git assume HEAD.
For example, you can get the same results as in the previous example by typing `git log origin/master..` – Git substitutes HEAD if one side is missing.

===== Multiple Points

The double-dot syntax is useful as a shorthand; but perhaps you want to specify more than two branches to indicate your revision, such as seeing what commits are in any of several branches that aren’t in the branch you’re currently on.
Git allows you to do this by using either the `^` character or `--not` before any reference from which you don’t want to see reachable commits.
Thus these three commands are equivalent:

[source,console]
----
$ git log refA..refB
$ git log ^refA refB
$ git log refB --not refA
----

This is nice because with this syntax you can specify more than two references in your query, which you cannot do with the double-dot syntax.
For instance, if you want to see all commits that are reachable from `refA` or `refB` but not from `refC`, you can type one of these:

[source,console]
----
$ git log refA refB ^refC
$ git log refA refB --not refC
----

This makes for a very powerful revision query system that should help you figure out what is in your branches.

[[_triple_dot]]
===== Triple Dot

The last major range-selection syntax is the triple-dot syntax, which specifies all the commits that are reachable by either of two references but not by both of them.
Look back at the example commit history in <<double_dot>>.
If you want to see what is in `master` or `experiment` but not any common references, you can run

[source,console]
----
$ git log master...experiment
F
E
D
C
----

Again, this gives you normal `log` output but shows you only the commit information for those four commits, appearing in the traditional commit date ordering.

A common switch to use with the `log` command in this case is `--left-right`, which shows you which side of the range each commit is in.
This helps make the data more useful:

[source,console]
----
$ git log --left-right master...experiment
< F
< E
> D
> C
----

With these tools, you can much more easily let Git know what commit or commits you want to inspect.


[[_interactive_staging]]
=== Interactive Staging

Git comes with a couple of scripts that make some command-line tasks easier.
Here, you’ll look at a few interactive commands that can help you easily craft your commits to include only certain combinations and parts of files.
These tools are very helpful if you modify a bunch of files and then decide that you want those changes to be in several focused commits rather than one big messy commit.
This way, you can make sure your commits are logically separate changesets and can be easily reviewed by the developers working with you.
If you run `git add` with the `-i` or `--interactive` option, Git goes into an interactive shell mode, displaying something like this:

[source,console]
----
$ git add -i
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now>
----

You can see that this command shows you a much different view of your staging area – basically the same information you get with `git status` but a bit more succinct and informative.
It lists the changes you’ve staged on the left and unstaged changes on the right.

After this comes a Commands section.
Here you can do a number of things, including staging files, unstaging files, staging parts of files, adding untracked files, and seeing diffs of what has been staged.

==== Staging and Unstaging Files

If you type `2` or `u` at the `What now>` prompt, the script prompts you for which files you want to stage:

[source,console]
----
What now> 2
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>
----

To stage the TODO and index.html files, you can type the numbers:

[source,console]
----
Update>> 1,2
           staged     unstaged path
* 1:    unchanged        +0/-1 TODO
* 2:    unchanged        +1/-1 index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Update>>
----

The `*` next to each file means the file is selected to be staged.
If you press Enter after typing nothing at the `Update>>` prompt, Git takes anything selected and stages it for you:

[source,console]
----
Update>>
updated 2 paths

*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 1
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
----

Now you can see that the TODO and index.html files are staged and the simplegit.rb file is still unstaged.
If you want to unstage the TODO file at this point, you use the `3` or `r` (for revert) option:

[source,console]
----
*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 3
           staged     unstaged path
  1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> 1
           staged     unstaged path
* 1:        +0/-1      nothing TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
Revert>> [enter]
reverted one path
----

Looking at your Git status again, you can see that you’ve unstaged the TODO file:

[source,console]
----
*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 1
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:    unchanged        +5/-1 lib/simplegit.rb
----

To see the diff of what you’ve staged, you can use the `6` or `d` (for diff) command.
It shows you a list of your staged files, and you can select the ones for which you would like to see the staged diff.
This is much like specifying `git diff --cached` on the command line:

[source,console]
----
*** Commands ***
  1: status     2: update      3: revert     4: add untracked
  5: patch      6: diff        7: quit       8: help
What now> 6
           staged     unstaged path
  1:        +1/-1      nothing index.html
Review diff>> 1
diff --git a/index.html b/index.html
index 4d07108..4335f49 100644
--- a/index.html
+++ b/index.html
@@ -16,7 +16,7 @@ Date Finder

 <p id="out">...</p>

-<div id="footer">contact : support@github.com</div>
+<div id="footer">contact : email.support@github.com</div>

 <script type="text/javascript">
----

With these basic commands, you can use the interactive add mode to deal with your staging area a little more easily.

==== Staging Patches

It’s also possible for Git to stage certain parts of files and not the rest.
For example, if you make two changes to your simplegit.rb file and want to stage one of them and not the other, doing so is very easy in Git.
From the interactive prompt, type `5` or `p` (for patch).
Git will ask you which files you would like to partially stage; then, for each section of the selected files, it will display hunks of the file diff and ask if you would like to stage them, one by one:

[source,console]
----
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index dd5ecc4..57399e0 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -22,7 +22,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log -n 25 #{treeish}")
+    command("git log -n 30 #{treeish}")
   end

   def blame(path)
Stage this hunk [y,n,a,d,/,j,J,g,e,?]?
----

You have a lot of options at this point.
Typing `?` shows a list of what you can do:

[source,console]
----
Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ?
y - stage this hunk
n - do not stage this hunk
a - stage this and all the remaining hunks in the file
d - do not stage this hunk nor any of the remaining hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
k - leave this hunk undecided, see previous undecided hunk
K - leave this hunk undecided, see previous hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
----

Generally, you’ll type `y` or `n` if you want to stage each hunk, but staging all of them in certain files or skipping a hunk decision until later can be helpful too.
If you stage one part of the file and leave another part unstaged, your status output will look like this:

[source,console]
----
What now> 1
           staged     unstaged path
  1:    unchanged        +0/-1 TODO
  2:        +1/-1      nothing index.html
  3:        +1/-1        +4/-0 lib/simplegit.rb
----

The status of the simplegit.rb file is interesting.
It shows you that a couple of lines are staged and a couple are unstaged.
You’ve partially staged this file.
At this point, you can exit the interactive adding script and run `git commit` to commit the partially staged files.

You also don’t need to be in interactive add mode to do the partial-file staging – you can start the same script by using `git add -p` or `git add --patch` on the command line.

Furthermore, you can use patch mode for partially resetting files with the `reset --patch` command, for checking out parts of files with the `checkout --patch` command and for stashing parts of files with the `stash save --patch` command.
We'll go into more details on each of these as we get to more advanced usages of these commands.


[[_git_stashing]]
=== Stashing and Cleaning

Often, when you’ve been working on part of your project, things are in a messy state and you want to switch branches for a bit to work on something else.
The problem is, you don’t want to do a commit of half-done work just so you can get back to this point later.
The answer to this issue is the `git stash` command.

Stashing takes the dirty state of your working directory – that is, your modified tracked files and staged changes – and saves it on a stack of unfinished changes that you can reapply at any time.

==== Stashing Your Work

To demonstrate, you’ll go into your project and start working on a couple of files and possibly stage one of the changes.
If you run `git status`, you can see your dirty state:

[source,console]
----
$ git status
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   lib/simplegit.rb
----

Now you want to switch branches, but you don’t want to commit what you’ve been working on yet; so you’ll stash the changes.
To push a new stash onto your stack, run `git stash` or `git stash save`:

[source,console]
----
$ git stash
Saved working directory and index state \
  "WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")
----

Your working directory is clean:

[source,console]
----
$ git status
# On branch master
nothing to commit, working directory clean
----

At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack.
To see which stashes you’ve stored, you can use `git stash list`:

[source,console]
----
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
----

In this case, two stashes were done previously, so you have access to three different stashed works.
You can reapply the one you just stashed by using the command shown in the help output of the original stash command: `git stash apply`.
If you want to apply one of the older stashes, you can specify it by naming it, like this: `git stash apply stash@{2}`.
If you don’t specify a stash, Git assumes the most recent stash and tries to apply it:

[source,console]
----
$ git stash apply
On branch master
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   index.html
	modified:   lib/simplegit.rb

no changes added to commit (use "git add" and/or "git commit -a")
----

You can see that Git re-modifies the files you reverted when you saved the stash.
In this case, you had a clean working directory when you tried to apply the stash, and you tried to apply it on the same branch you saved it from; but having a clean working directory and applying it on the same branch aren’t necessary to successfully apply a stash.
You can save a stash on one branch, switch to another branch later, and try to reapply the changes.
You can also have modified and uncommitted files in your working directory when you apply a stash – Git gives you merge conflicts if anything no longer applies cleanly.

The changes to your files were reapplied, but the file you staged before wasn’t restaged.
To do that, you must run the `git stash apply` command with a `--index` option to tell the command to try to reapply the staged changes.
If you had run that instead, you’d have gotten back to your original position:

[source,console]
----
$ git stash apply --index
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   lib/simplegit.rb
----

The apply option only tries to apply the stashed work – you continue to have it on your stack.
To remove it, you can run `git stash drop` with the name of the stash to remove:

[source,console]
----
$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051 Revert "added file_size"
stash@{2}: WIP on master: 21d80a5 added number to log
$ git stash drop stash@{0}
Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43)
----

You can also run `git stash pop` to apply the stash and then immediately drop it from your stack.

==== Creative Stashing

There are a few stash variants that may also be helpful.
The first option that is quite popular is the `--keep-index` option to the `stash save` command.
This tells Git to not stash anything that you've already staged with the `git add` command.

This can be really helpful if you've made a number of changes but want to only commit some of them and then come back to the rest of the changes at a later time.

[source,console]
----
$ git status -s
M  index.html
 M lib/simplegit.rb

$ git stash --keep-index
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
M  index.html
----

Another common thing you may want to do with stash is to stash the untracked files as well as the tracked ones.
By default, `git stash` will only store files that are already in the index.
If you specify `--include-untracked` or `-u`, Git will also stash any untracked files you have created.

[source,console]
----
$ git status -s
M  index.html
 M lib/simplegit.rb
?? new-file.txt

$ git stash -u
Saved working directory and index state WIP on master: 1b65b17 added the index file
HEAD is now at 1b65b17 added the index file

$ git status -s
$
----

Finally, if you specify the `--patch` flag, Git will not stash everything that is modified but will instead prompt you interactively which of the changes you would like to stash and which you would like to keep in your working directory.

[source,console]
----
$ git stash --patch
diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 66d332e..8bb5674 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -16,6 +16,10 @@ class SimpleGit
         return `#{git_cmd} 2>&1`.chomp
       end
     end
+
+    def show(treeish = 'master')
+      command("git show #{treeish}")
+    end

 end
 test
Stash this hunk [y,n,q,a,d,/,e,?]? y

Saved working directory and index state WIP on master: 1b65b17 added the index file
----

==== Creating a Branch from a Stash

If you stash some work, leave it there for a while, and continue on the branch from which you stashed the work, you may have a problem reapplying the work.
If the apply tries to modify a file that you’ve since modified, you’ll get a merge conflict and will have to try to resolve it.
If you want an easier way to test the stashed changes again, you can run `git stash branch`, which creates a new branch for you, checks out the commit you were on when you stashed your work, reapplies your work there, and then drops the stash if it applies successfully:

[source,console]
----
$ git stash branch testchanges
M	index.html
M	lib/simplegit.rb
Switched to a new branch 'testchanges'
On branch testchanges
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	modified:   index.html

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   lib/simplegit.rb

Dropped refs/stash@{0} (29d385a81d163dfd45a452a2ce816487a6b8b014)
----

This is a nice shortcut to recover stashed work easily and work on it in a new branch.

[[_git_clean]]
==== Cleaning your Working Directory

Finally, you may not want to stash some work or files in your working directory, but simply get rid of them.
The `git clean` command will do this for you.

Some common reasons for this might be to remove cruft that has been generated by merges or external tools or to remove build artifacts in order to run a clean build.

You'll want to be pretty careful with this command, since it's designed to remove files from your working directory that are not tracked.
If you change your mind, there is often no retrieving the content of those files.
A safer option is to run `git stash --all` to remove everything but save it in a stash.

Assuming you do want to remove cruft files or clean your working directory, you can do so with `git clean`.
To remove all the untracked files in your working directory, you can run `git clean -f -d`, which removes any files and also any subdirectories that become empty as a result.
The `-f` means 'force' or "really do this".

If you ever want to see what it would do, you can run the command with the `-n` option, which means ``do a dry run and tell me what you _would_ have removed''.

[source,console]
----
$ git clean -d -n
Would remove test.o
Would remove tmp/
----

By default, the `git clean` command will only remove untracked files that are not ignored.
Any file that matches a pattern in your `.gitignore` or other ignore files will not be removed.
If you want to remove those files too, such as to remove all `.o` files generated from a build so you can do a fully clean build, you can add a `-x` to the clean command.

[source,console]
----
$ git status -s
 M lib/simplegit.rb
?? build.TMP
?? tmp/

$ git clean -n -d
Would remove build.TMP
Would remove tmp/

$ git clean -n -d -x
Would remove build.TMP
Would remove test.o
Would remove tmp/
----

If you don't know what the `git clean` command is going to do, always run it with a `-n` first to double check before changing the `-n` to a `-f` and doing it for real.
The other way you can be careful about the process is to run it with the `-i` or ``interactive'' flag.

This will run the clean command in an interactive mode.

[source,console]
----
$ git clean -x -i
Would remove the following items:
  build.TMP  test.o
*** Commands ***
    1: clean                2: filter by pattern    3: select by numbers    4: ask each             5: quit
    6: help
What now>
----

This way you can step through each file individually or specify patterns for deletion interactively.


[[_signing]]
=== Signing Your Work

Git is cryptographically secure, but it's not foolproof.
If you're taking work from others on the internet and want to verify that commits are actually from a trusted source, Git has a few ways to sign and verify work using GPG.

==== GPG Introduction

First of all, if you want to sign anything you need to get GPG configured and your personal key installed.

[source,console]
----
$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg

pub 2048R/0A46826A 2014-06-04 uid Scott Chacon (Git signing key) <schacon@gmail.com> sub 2048R/874529A9 2014-06-04

If you don't have a key installed, you can generate one with `gpg --gen-key`.

[source,console]

gpg --gen-key

Once you have a private key to sign with, you can configure Git to use it for signing things by setting the `user.signingkey` config setting.

[source,console]

git config --global user.signingkey 0A46826A

Now Git will use your key by default to sign tags and commits if you want.

==== Signing Tags

If you have a GPG private key setup, you can now use it to sign new tags.
All you have to do is use `-s` instead of `-a`:

[source,console]

$ git tag -s v1.5 -m my signed 1.5 tag

You need a passphrase to unlock the secret key for user: "Ben Straub <ben@straub.cc>" 2048-bit RSA key, ID 800430EB, created 2014-05-04

If you run `git show` on that tag, you can see your GPG signature attached to it:

[source,console]
--------
$ git show v1.5
tag v1.5
Tagger: Ben Straub <ben@straub.cc>
Date:   Sat May 3 20:29:41 2014 -0700

my signed 1.5 tag
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQEcBAABAgAGBQJTZbQlAAoJEF0+sviABDDrZbQH/09PfE51KPVPlanr6q1v4/Ut
LQxfojUWiLQdg2ESJItkcuweYg+kc3HCyFejeDIBw9dpXt00rY26p05qrpnG+85b
hM1/PswpPLuBSr+oCIDj5GMC2r2iEKsfv2fJbNW8iWAXVLoWZRF8B0MfqX/YTMbm
ecorc4iXzQu7tupRihslbNkfvfciMnSDeSvzCpWAHl7h8Wj6hhqePmLm9lAYqnKp
8S5B/1SSQuEAjRZgI4IexpZoeKGVDptPHxLLS38fozsyi0QyDyzEgJxcJQVMXxVi
RUysgqjcpT8+iQM1PblGfHR4XAhuOqN5Fx06PSaFZhqvWFezJ28/CLyX5q+oIVk=
=EFTF
-----END PGP SIGNATURE-----

commit ca82a6dff817ec66f44342007202690a93763949
Author: Scott Chacon <schacon@gee-mail.com>
Date:   Mon Mar 17 21:52:11 2008 -0700

    changed the version number
--------

==== Verifying Tags

To verify a signed tag, you use `git tag -v [tag-name]`.
This command uses GPG to verify the signature.
You need the signer’s public key in your keyring for this to work properly:

[source,console]

$ git tag -v v1.4.2.1 object 883653babd8ee7ea23e6a5c392bb739348b1eb61 type commit tag v1.4.2.1 tagger Junio C Hamano <junkio@cox.net> 1158138501 -0700

GIT 1.4.2.1

Minor fixes since 1.4.2, including git-mv and git-http with alternates. gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A gpg: Good signature from "Junio C Hamano <junkio@cox.net>" gpg: aka "[jpeg image of size 1513]" Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A

If you don’t have the signer’s public key, you get something like this instead:

[source,console]

gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A gpg: Can’t check signature: public key not found error: could not verify the tag v1.4.2.1

[[_signing_commits]]
==== Signing Commits

In more recent versions of Git (v1.7.9 and above), you can now also sign individual commits.
If you're interested in signing commits directly instead of just the tags, all you need to do is add a `-S` to your `git commit` command.

[source,console]

$ git commit -a -S -m signed commit

You need a passphrase to unlock the secret key for user: "Scott Chacon (Git signing key) <schacon@gmail.com>" 2048-bit RSA key, ID 0A46826A, created 2014-06-04

[master 5c3386c] signed commit 4 files changed, 4 insertions(+), 24 deletions(-) rewrite Rakefile (100%) create mode 100644 lib/git.rb

To see and verify these signatures, there is also a `--show-signature` option to `git log`.

[source,console]

$ git log --show-signature -1 commit 5c3386cf54bba0a33a32da706aa52bc0155503c2 gpg: Signature made Wed Jun 4 19:49:17 2014 PDT using RSA key ID 0A46826A gpg: Good signature from "Scott Chacon (Git signing key) <schacon@gmail.com>" Author: Scott Chacon <schacon@gmail.com> Date: Wed Jun 4 19:49:17 2014 -0700

signed commit
Additionally, you can configure `git log` to check any signatures it finds and list them in its output with the `%G?` format.

[source,console]

$ git log --pretty="format:%h %G? %aN %s"

5c3386c G Scott Chacon signed commit ca82a6d N Scott Chacon changed the version number 085bb3b N Scott Chacon removed unnecessary test code a11bef0 N Scott Chacon first commit

Here we can see that only the latest commit is signed and valid and the previous commits are not.

In Git 1.8.3 and later, "git merge" and "git pull" can be told to inspect and reject when merging a commit that does not carry a trusted GPG signature with the `--verify-signatures` command.

If you use this option when merging a branch and it contains commits that are not signed and valid, the merge will not work.

[source,console]

$ git merge --verify-signatures non-verify fatal: Commit ab06180 does not have a GPG signature.

If the merge contains only valid signed commits, the merge command will show you all the signatures it has checked and then move forward with the merge.

[source,console]

$ git merge --verify-signatures signed-branch Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <schacon@gmail.com> Updating 5c3386c..13ad65e Fast-forward README | 2 + 1 file changed, 2 insertions()

You can also use the `-S` option with the `git merge` command itself to sign the resulting merge commit itself.
The following example both verifies that every commit in the branch to be merged is signed and furthermore signs the resulting merge commit.

[source,console]

$ git merge --verify-signatures -S signed-branch Commit 13ad65e has a good GPG signature by Scott Chacon (Git signing key) <schacon@gmail.com>

You need a passphrase to unlock the secret key for user: "Scott Chacon (Git signing key) <schacon@gmail.com>" 2048-bit RSA key, ID 0A46826A, created 2014-06-04

Merge made by the recursive strategy. README | 2 + 1 file changed, 2 insertions()

==== Everyone Must Sign

Signing tags and commits is great, but if you decide to use this in your normal workflow, you'll have to make sure that everyone on your team understands how to do so.
If you don't, you'll end up spending a lot of time helping people figure out how to rewrite their commits with signed versions.
Make sure you understand GPG and the benefits of signing things before adopting this as part of your standard workflow.


[[_searching]]
=== Searching

With just about any size codebase, you'll often need to find where a function is called or defined, or find the history of a method.
Git provides a couple of useful tools for looking through the code and commits stored in its database quickly and easily.
We'll go through a few of them.

[[_git_grep]]
==== Git Grep

Git ships with a command called `grep` that allows you to easily search through any committed tree or the working directory for a string or regular expression.
For these examples, we'll look through the Git source code itself.

By default, it will look through the files in your working directory.
You can pass `-n` to print out the line numbers where Git has found matches.

[source,console]

$ git grep -n gmtime_r compat/gmtime.c:3:#undef gmtime_r compat/gmtime.c:8: return git_gmtime_r(timep, &result); compat/gmtime.c:11:struct tm *git_gmtime_r(const time_t *timep, struct tm *result) compat/gmtime.c:16: ret = gmtime_r(timep, result); compat/mingw.c:606:struct tm *gmtime_r(const time_t *timep, struct tm *result) compat/mingw.h:162:struct tm *gmtime_r(const time_t *timep, struct tm *result); date.c:429: if (gmtime_r(&now, &now_tm)) date.c:492: if (gmtime_r(&time, tm)) { git-compat-util.h:721:struct tm *git_gmtime_r(const time_t *, struct tm *); git-compat-util.h:723:#define gmtime_r git_gmtime_r

There are a number of interesting options you can provide the `grep` command.

For instance, instead of the previous call, you can have Git summarize the output by just showing you which files matched and how many matches there were in each file with the `--count` option:

[source,console]

$ git grep --count gmtime_r compat/gmtime.c:4 compat/mingw.c:1 compat/mingw.h:1 date.c:2 git-compat-util.h:2

If you want to see what method or function it thinks it has found a match in, you can pass `-p`:

[source,console]

$ git grep -p gmtime_r *.c date.c=static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm) date.c: if (gmtime_r(&now, &now_tm)) date.c=static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt) date.c: if (gmtime_r(&time, tm)) {

So here we can see that `gmtime_r` is called in the `match_multi_number` and `match_digit` functions in the date.c file.

You can also look for complex combinations of strings with the `--and` flag, which makes sure that multiple matches are in the same line.
For instance, let's look for any lines that define a constant with either the strings ``LINK'' or ``BUF_MAX'' in them in the Git codebase in an older 1.8.0 version.

Here we'll also use the `--break` and `--heading` options which help split up the output into a more readable format.

[source,console]

$ git grep --break --heading \ -n -e #define --and \( -e LINK -e BUF_MAX \) v1.8.0 v1.8.0:builtin/index-pack.c 62:#define FLAG_LINK (1u<<20)

v1.8.0:cache.h 73:#define S_IFGITLINK 0160000 74:#define S_ISGITLINK(m) (((m) & S_IFMT) == S_IFGITLINK)

v1.8.0:environment.c 54:#define OBJECT_CREATION_MODE OBJECT_CREATION_USES_HARDLINKS

v1.8.0:strbuf.c 326:#define STRBUF_MAXLINK (2*PATH_MAX)

v1.8.0:symlinks.c 53:#define FL_SYMLINK (1 << 2)

v1.8.0:zlib.c 30:/* #define ZLIB_BUF_MAX ((uInt)-1) / 31:#define ZLIB_BUF_MAX ((uInt) 1024 * 1024 * 1024) / 1GB */

The `git grep` command has a few advantages over normal searching commands like `grep` and `ack`.
The first is that it's really fast, the second is that you can search through any tree in Git, not just the working directory.
As we saw in the above example, we looked for terms in an older version of the Git source code, not the version that was currently checked out.

==== Git Log Searching

Perhaps you're looking not for *where* a term exists, but *when* it existed or was introduced.
The `git log` command has a number of powerful tools for finding specific commits by the content of their messages or even the content of the diff they introduce.

If we want to find out for example when the `ZLIB_BUF_MAX` constant was originally introduced, we can tell Git to only show us the commits that either added or removed that string with the `-S` option.

[source,console]

$ git log -SZLIB_BUF_MAX --oneline e01503b zlib: allow feeding more than 4GB in one go ef49a7a zlib: zlib can only process 4GB at a time

If we look at the diff of those commits we can see that in `ef49a7a` the constant was introduced and in `e01503b` it was modified.

If you need to be more specific, you can provide a regular expression to search for with the `-G` option.

===== Line Log Search

Another fairly advanced log search that is insanely useful is the line history search.
This is a fairly recent addition and not very well known, but it can be really helpful.
It is called with the `-L` option to `git log` and will show you the history of a function or line of code in your codebase.

For example, if we wanted to see every change made to the function `git_deflate_bound` in the `zlib.c` file, we could run `git log -L :git_deflate_bound:zlib.c`.
This will try to figure out what the bounds of that function are and then look through the history and show us every change that was made to the function as a series of patches back to when the function was first created.

[source,console]

$ git log -L :git_deflate_bound:zlib.c commit ef49a7a0126d64359c974b4b3b71d7ad42ee3bca Author: Junio C Hamano <gitster@pobox.com> Date: Fri Jun 10 11:52:15 2011 -0700

zlib: zlib can only process 4GB at a time

diff --git a/zlib.c b/zlib.c --- a/zlib.c + b/zlib.c @@ -85,5 +130,5 @@ -unsigned long git_deflate_bound(z_streamp strm, unsigned long size) +unsigned long git_deflate_bound(git_zstream *strm, unsigned long size) { - return deflateBound(strm, size); + return deflateBound(&strm→z, size); }

commit 225a6f1068f71723a910e8565db4e252b3ca21fa Author: Junio C Hamano <gitster@pobox.com> Date: Fri Jun 10 11:18:17 2011 -0700

zlib: wrap deflateBound() too

diff --git a/zlib.c b/zlib.c --- a/zlib.c + b/zlib.c @@ -81,0 +85,5 @@ +unsigned long git_deflate_bound(z_streamp strm, unsigned long size) +{ + return deflateBound(strm, size); +}

+

If Git can't figure out how to match a function or method in your programming language, you can also provide it a regex.
For example, this would have done the same thing: `git log -L '/unsigned long git_deflate_bound/',/^}/:zlib.c`.
You could also give it a range of lines or a single line number and you'll get the same sort of output.


[[_rewriting_history]]
=== Rewriting History

Many times, when working with Git, you may want to revise your commit history for some reason.
One of the great things about Git is that it allows you to make decisions at the last possible moment.
You can decide what files go into which commits right before you commit with the staging area, you can decide that you didn’t mean to be working on something yet with the stash command, and you can rewrite commits that already happened so they look like they happened in a different way.
This can involve changing the order of the commits, changing messages or modifying files in a commit, squashing together or splitting apart commits, or removing commits entirely – all before you share your work with others.

In this section, you’ll cover how to accomplish these very useful tasks so that you can make your commit history look the way you want before you share it with others.

[[_git_amend]]
==== Changing the Last Commit

Changing your last commit is probably the most common rewriting of history that you’ll do.
You’ll often want to do two basic things to your last commit: change the commit message, or change the snapshot you just recorded by adding, changing and removing files.

If you only want to modify your last commit message, it’s very simple:

[source,console]

$ git commit --amend

That drops you into your text editor, which has your last commit message in it, ready for you to modify the message.
When you save and close the editor, the editor writes a new commit containing that message and makes it your new last commit.

If you’ve committed and then you want to change the snapshot you committed by adding or changing files, possibly because you forgot to add a newly created file when you originally committed, the process works basically the same way.
You stage the changes you want by editing a file and running `git add` on it or `git rm` to a tracked file, and the subsequent `git commit --amend` takes your current staging area and makes it the snapshot for the new commit.

You need to be careful with this technique because amending changes the SHA-1 of the commit.
It’s like a very small rebase – don’t amend your last commit if you’ve already pushed it.

[[_changing_multiple]]
==== Changing Multiple Commit Messages

To modify a commit that is farther back in your history, you must move to more complex tools.
Git doesn’t have a modify-history tool, but you can use the rebase tool to rebase a series of commits onto the HEAD they were originally based on instead of moving them to another one.
With the interactive rebase tool, you can then stop after each commit you want to modify and change the message, add files, or do whatever you wish.
You can run rebase interactively by adding the `-i` option to `git rebase`.
You must indicate how far back you want to rewrite commits by telling the command which commit to rebase onto.

For example, if you want to change the last three commit messages, or any of the commit messages in that group, you supply as an argument to `git rebase -i` the parent of the last commit you want to edit, which is `HEAD~2^` or `HEAD~3`.
It may be easier to remember the `~3` because you’re trying to edit the last three commits; but keep in mind that you’re actually designating four commits ago, the parent of the last commit you want to edit:

[source,console]

$ git rebase -i HEAD~3

Remember again that this is a rebasing command – every commit included in the range `HEAD~3..HEAD` will be rewritten, whether you change the message or not.
Don’t include any commit you’ve already pushed to a central server – doing so will confuse other developers by providing an alternate version of the same change.

Running this command gives you a list of commits in your text editor that looks something like this:

[source,console]

pick f7f3f6d changed my name a bit pick 310154e updated README formatting and added blame pick a5f4a0d added cat-file