39155
Kommentar:
|
← Revision 24 vom 2015-04-16 09:10:29 ⇥
39097
|
Gelöschter Text ist auf diese Art markiert. | Hinzugefügter Text ist auf diese Art markiert. |
Zeile 4: | Zeile 4: |
||<style="border: none;"> <<TableOfContents()>> ||<style="border: none;"> {{attachment:Git-Logo-2Color.png||width=600}} || | ||<style="border: none;"> <<TableOfContents()>> ||<style="border: none;"> {{attachment:Git-Logo-2Color.png||width=400}} || |
Zeile 46: | Zeile 46: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 50: | Zeile 50: |
Initialized empty Git repository in /home/alice/hello_python/.git/ }}} |
Initialized empty Git repository in /home/alice/hello_python/.git/}}} |
Zeile 55: | Zeile 54: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 66: | Zeile 65: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 77: | Zeile 76: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 100: | Zeile 99: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 110: | Zeile 109: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 117: | Zeile 116: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 133: | Zeile 132: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 149: | Zeile 148: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 158: | Zeile 157: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 174: | Zeile 173: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 187: | Zeile 186: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 189: | Zeile 188: |
alice@git-workshop:~/hello_python$ cat hello.py | }}} {{{#!highlight python |
Zeile 193: | Zeile 193: |
}}} {{{#!highlight sh |
|
Zeile 202: | Zeile 204: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 219: | Zeile 221: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 238: | Zeile 240: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 247: | Zeile 249: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 266: | Zeile 268: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 285: | Zeile 287: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 305: | Zeile 307: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 341: | Zeile 343: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 362: | Zeile 364: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 371: | Zeile 373: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 381: | Zeile 383: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 395: | Zeile 397: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 397: | Zeile 399: |
bob@git-workshop:~/hello_python$ cat hello.py | }}} {{{#!highlight python |
Zeile 408: | Zeile 411: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 425: | Zeile 428: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 456: | Zeile 459: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 464: | Zeile 467: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 487: | Zeile 490: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 508: | Zeile 511: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 514: | Zeile 517: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 527: | Zeile 530: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 542: | Zeile 545: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 547: | Zeile 550: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 563: | Zeile 566: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 578: | Zeile 581: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 611: | Zeile 614: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 625: | Zeile 628: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 632: | Zeile 635: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 654: | Zeile 657: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 675: | Zeile 678: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 686: | Zeile 689: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 736: | Zeile 739: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 738: | Zeile 741: |
alice@git-workshop:~/hello_python$ cat hello.py | }}} {{{#!highlight python |
Zeile 757: | Zeile 761: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 766: | Zeile 770: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 780: | Zeile 784: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 788: | Zeile 792: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 810: | Zeile 814: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 816: | Zeile 820: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 823: | Zeile 827: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 834: | Zeile 838: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 856: | Zeile 860: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 862: | Zeile 866: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 872: | Zeile 876: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 899: | Zeile 903: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 924: | Zeile 928: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 926: | Zeile 930: |
bob@git-workshop:~/hello_python$ cat hello.py | }}} {{{#!highlight python |
Zeile 948: | Zeile 953: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 960: | Zeile 965: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 994: | Zeile 999: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1011: | Zeile 1016: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1022: | Zeile 1027: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1029: | Zeile 1034: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1050: | Zeile 1055: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1064: | Zeile 1069: |
{{{#!highlight bash | {{{#!highlight sh |
Zeile 1084: | Zeile 1089: |
Ein Cheatsheet mit den gängigsten Befehlen findet ihr unter [[attachment:git-cheatsheet.pdf]]. | Ein Cheatsheet mit den gängigsten Befehlen findet ihr unter [[attachment:git-cheatsheet.pdf]]. |
Zeile 1089: | Zeile 1095: |
Entwickelt zusammen ein Trainingsprogramm für arithmetische Aufgaben (Grundrechenarten). Dabei sollen nur ganzzahlige Operanden vorkommen. Dem Nutzer soll es ermöglicht werden, die Anzahl und Art der gestellten Aufgaben zu bestimmen (sprich: wie viele Aufgaben und was für Grundrechenarten?). Dabei soll die Anzahl der richtigen Ergebnisse gezählt werden und dem Nutzer am Ende eine kurze Statistik präsentiert werden. Falls Fragen oder Unklarheiten aufkommen, dann versucht im Team einen Konsens über die eurer Meinung nach sinnvollste Lösung zu finden und fragt erst dann. Nutzt git und das interne [[https://git.hack-hro.de|GitLab]] für die Zusammenarbeit. Die Wahl der Programmiersprache und der Benutzerschnittstelle sind euch freigestellt. Ich wäre sehr erfreut, wenn ein Teammitglied das Programm und die Zusammenarbeit im Team am Ende vorstellt. |
Entwickelt zusammen ein Trainingsprogramm für arithmetische Aufgaben (Grundrechenarten). Dabei sollen nur ganzzahlige Operanden vorkommen. Dem Nutzer soll es ermöglicht werden, die Anzahl und Art der gestellten Aufgaben zu bestimmen (sprich: wie viele Aufgaben und was für Grundrechenarten). Dabei soll die Anzahl der richtigen Ergebnisse gezählt und dem Nutzer am Ende eine kurze Statistik präsentiert werden. Falls Fragen oder Unklarheiten aufkommen, dann versucht im Team einen Konsens über die eurer Meinung nach sinnvollste Lösung zu finden und fragt erst dann. Nutzt git und das interne [[https://git.hack-hro.de|GitLab]] für die Zusammenarbeit. Die Wahl der Programmiersprache und der Benutzerschnittstelle sind euch freigestellt. Ich wäre sehr erfreut, wenn ein Teammitglied das Programm und die Zusammenarbeit im Team am Ende vorstellt. = Feedback = Bevor ihr geht, beantwortet bitte noch schnell [[http://goo.gl/forms/2nikbRT5Da|diese 4+1 Fragen]]. Danke! |
Inhaltsverzeichnis
|
|
Info
- Thema
- Einführung in git
- Vortragende
- Datum
- 22.04.2015
- Beschreibung
- Die freie Versionsverwaltungssoftware git erfreut sich seit ihrem Erscheinen größter Beliebtheit und hat die Art und Weise, wie Software entwickelt wird, regelrecht revolutioniert. In diesem Workshop wollen wir etwas über die Geschichte von git erfahren, die Basics kennenlernen und in kleinen Teams kollaborativ arbeiten.
Themen
- Entstehungsgeschichte
- allerlei Umgang (anlegen, klonen, stagen, committen, resetten, pullen, …)
- Eigenarbeit in Kleingruppen
Inhalt
Entstehungsgeschichte
Ziemlich genau 10 Jahre ist es her, als git das Licht der Welt erblickte. Damals wurde bei der Entwicklung des Linux-Kernels ein proprietäres Programm namens „BitKeeper“ eingesetzt. Obwohl es unüblich ist proprietäre Programm im Umfeld freier Software einzusetzen, entschied sich Linus Torvalds aus Gründen dafür. Der Deal war wie folgt: BitKeeper durfte für die Entwicklung des Kernels kostenlos genutzt werden, wenn diese nicht versuchen würden es zu reverse-engineeren.
Es kam, wie es kommen musste: das GNU war stark in Andrew "Tridge" Tridgell und er forschte/experimentierte/spielte zu viel mit BitKeeper herum, sodass Larry McVoy die Lizenz änderte und BitKeeper damit für die Kernelentwicklung aus dem Rennen war.
Linus stoppte die Kernelentwicklung und schaute sich nach alternativen Source Control Management Systemen um. Jedoch fand er nichts, was seinen Ansprüchen genügte. Also sagte er: „Ich kann in 2 Wochen etwas bauen, was besser als alles andere da draußen ist.“ Und er sollte recht behalten.
Alice sagt "Hallo"
Alice hat gerade angefangen Python zu lernen und möchte ihr erstes Programm schreiben. Dies ist natürlich ein "hello world" Programm. Zum Glück kann Alice schon mit git umgehen, daher nutzt sie es um ihre Zwischenergebnisse festzuhalten.
Zu Beginn legt Alice ein Verzeichnis und darin ein git-Repository an:
Darin fängt sie an zu programmieren:
Die ersten Gehversuche laufen prächtig, also fügt sie die Datei hello.py zu der staging area hinzu.
1 alice@git-workshop:~/hello_python$ git add hello.py
Die staging area enthält alle Änderungen, die beim nächsten Commit eingepflegt werden sollen. Dieser Zwischenschritt ist sinnvoll, weil Alice so sehr genau festlegen kann, was sie committen möchte und was nicht. Wir schauen uns gleich an, wie wir die staging area inspizieren können.
Nach dem Hinzufügen zur staging area committet Alice die Änderungen:
1 alice@git-workshop:~/hello_python$ git commit
2
3 *** Please tell me who you are.
4
5 Run
6
7 git config --global user.email "you@example.com"
8 git config --global user.name "Your Name"
9
10 to set your account's default identity.
11 Omit --global to set the identity only in this repository.
12
13 fatal: unable to auto-detect email address (got 'alice@git-workshop.(none)')
Uh oh ... Alice hat vor lauter Eifer git gar nicht konfiguriert. Für einen Commit braucht git nämlich mindestens einen Namen und eine E-Mail-Adresse. Schließlich soll die ganze Welt sehen können, wer dieses Programm geschrieben hat und an wen die Lobeshymnen zu schicken sind.
Dies holt sie schnell nach:
Danach versucht sie erneut zu committen:
1 alice@git-workshop:~/hello_python$ git commit
Es öffnet sich ihr Lieblingseditor und der fordert sie zum Eingeben einer commit message auf:
Alice erfreut sich daran, dass git ihr sagt, dass eine neue Datei namens hello.py erzeugt wurde und schreibt ihre commit message:
1 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
2 # Please enter the commit message for your changes. Lines starting
3 # with '#' will be ignored, and an empty message aborts the commit.
4 # On branch master
5 #
6 # Initial commit
7 #
8 # Changes to be committed:
9 # new file: hello.py
10 #
11
Sie speichert und schließt die Datei und git gibt Informationen über ihren Commit aus:
Alice möchte sich jetzt die Geschichte ihres Repository ansehen:
Die kurze Geschichte besteht aus einem einzigen Commit. Dieser wird durch einen SHA1-Wert gekennzeichnet (a9b1eee7a74fae95caa21f488a7d050f0e20d262). Weiterhin enthält der Commit Informationen über den Autor, das Datum, und die commit message, die Alice eingegeben hat.
Jetzt möchte Alice den aktuellen Status des Repository begutachten:
Git sagt ihr, dass sie sich gerade auf dem master-branch befindet und dass nichts zu committen oder sonst was zu sehen gäbe. Sie bleibt ruhig und macht weiter.
In einem Shell-Workshop ihres lokalen Hackspaces hat Alice gelernt, dass man einem Shellskript immer eine Shebangzeile hinzufügt. Sie ändert hello.py wieder mit ihrem Lieblingseditor und testet ihre Änderungen:
1 alice@git-workshop:~/hello_python$ vim hello.py
Alles funktioniert prächtig. Alice ist neugierig, ob git etwas von ihren Änderungen mitbekommen hat und erfragt den Status des Repository:
1 alice@git-workshop:~/hello_python$ git status
2 On branch master
3 Changes not staged for commit:
4 (use "git add <file>..." to update what will be committed)
5 (use "git checkout -- <file>..." to discard changes in working directory)
6
7 modified: hello.py
8
9 no changes added to commit (use "git add" and/or "git commit -a")
Git hat bemerkt, dass die Datei hello.py geändert wurde und gibt Alice ein paar Hinweise, was sie tun muss um die Änderungen zur staging area hinzuzufügen oder zu verwerfen.
Alice' Neugier geht aber noch weiter. Weiß git, was sich genau geändert hat? Dafür nutzt Alice git diff
Git zeigt nicht nur an, dass zwei Zeilen hinzugefügt wurden (die Zeilen mit dem +), sondern auch, dass sich die Berechtigungen der Datei geändert haben (new mode … old mode).
Die Neugier von Alice ist damit befriedigt. Sie fügt die Datei zur staging area hinzu und committet:
Wieder möchte sich Alice die Geschichte des Repository ansehen:
1 alice@git-workshop:~/hello_python$ git log
2 commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
3 Author: Alice Testington <alice@git-workshop>
4 Date: Fri Apr 10 17:14:47 2015 +0000
5
6 Fügt Shebangzeile hinzu.
7
8 commit a9b1eee7a74fae95caa21f488a7d050f0e20d262
9 Author: Alice Testington <alice@git-workshop>
10 Date: Fri Apr 10 16:19:22 2015 +0000
11
12 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Das Repository enthält nun zwei Commits, jeweils mit unterschiedlichen SHA1-Werten. Diese werden in zeitlicher Reihenfolge angezeigt (neueste zuerst).
Fasziniert von der Möglichkeit sich Unterschiede anzeigen lassen zu können, schaut sich Alice die Unterschiede zwischen ihren beiden Commits an:
1 alice@git-workshop:~/hello_python$ git diff a9b1eee7a74fae95caa21f488a7d050f0e20d262 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
2 diff --git a/hello.py b/hello.py
3 old mode 100644
4 new mode 100755
5 index ac754f5..13b0130
6 --- a/hello.py
7 +++ b/hello.py
8 @@ -1 +1,3 @@
9 +#!/usr/bin/env python3
10 +
11 print("Hello, world.")
Diesen Diff hat Alice vorhin schon gesehen. Es ist genau der gleiche, den sie vorhin mit git diff erzeugt hat. In diesem Fall zeigt git die Unterschiede von Commit a9b1eee7a74fae95caa21f488a7d050f0e20d262 bis zu Commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d an.
Alice fragt sich: „Was passiert, wenn ich die Commits vertausche?“
1 alice@git-workshop:~/hello_python$ git diff 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d a9b1eee7a74fae95caa21f488a7d050f0e20d262
2 diff --git a/hello.py b/hello.py
3 old mode 100755
4 new mode 100644
5 index 13b0130..ac754f5
6 --- a/hello.py
7 +++ b/hello.py
8 @@ -1,3 +1 @@
9 -#!/usr/bin/env python3
10 -
11 print("Hello, world.")
Erfreut stellt Alice fest, dass dies genau das ist, was sie erwartet hat. Während vom ersten zum zweiten Commit Zeilen hinzugefügt werden, werden vom zweiten zum ersten Commit Zeilen entfernt (die Zeilen mit dem -). Auch die Berechtigungen der Datei wurden berücksichtigt.
Alice möchte sich jetzt die Geschichte des Repository mit den dazugehörigen Änderungen ansehen:
1 alice@git-workshop:~/hello_python$ git log --patch
2 commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
3 Author: Alice Testington <alice@git-workshop>
4 Date: Fri Apr 10 17:14:47 2015 +0000
5
6 Fügt Shebangzeile hinzu.
7
8 diff --git a/hello.py b/hello.py
9 old mode 100644
10 new mode 100755
11 index ac754f5..13b0130
12 --- a/hello.py
13 +++ b/hello.py
14 @@ -1 +1,3 @@
15 +#!/usr/bin/env python3
16 +
17 print("Hello, world.")
18
19 commit a9b1eee7a74fae95caa21f488a7d050f0e20d262
20 Author: Alice Testington <alice@git-workshop>
21 Date: Fri Apr 10 16:19:22 2015 +0000
22
23 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
24
25 diff --git a/hello.py b/hello.py
26 new file mode 100644
27 index 0000000..ac754f5
28 --- /dev/null
29 +++ b/hello.py
30 @@ -0,0 +1 @@
31 +print("Hello, world.")
Weil Alice sich die Dinge gerne visualisiert, möchte sie sich den Graphen zur Geschichte anzeigen lassen:
1 alice@git-workshop:~/hello_python$ git log --graph
2 * commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
3 | Author: Alice Testington <alice@git-workshop>
4 | Date: Fri Apr 10 17:14:47 2015 +0000
5 |
6 | Fügt Shebangzeile hinzu.
7 |
8 * commit a9b1eee7a74fae95caa21f488a7d050f0e20d262
9 Author: Alice Testington <alice@git-workshop>
10 Date: Fri Apr 10 16:19:22 2015 +0000
11
12 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Alice ist sehr zufrieden mit ihrer Arbeit und erzählt ihrem Freund Bob von dem Projekt.
Bob sagt "Hallo, Alice!"
Alice' Freund Bob ist ein erfahrener Pythonista und schaut sich ihr Projekt an. Dazu klont er es in sein Home-Verzeichnis:
Bob kann dank git die gesamte Geschichte von Alice' Projekt sehen. Darüber hinaus ist in Bobs Repository ein Verweis zu Alice' Repository gespeichert:
Nun schaut sich Bob das Programm von Alice an und stellt fest, dass man das ja viel besser hätte machen können. Bob probiert folgendes aus:
An sich tut das Programm, was es soll. Aber wenn man es als Modul lädt, dann wird ebenfalls "Hello, world." ausgegeben. Um es "modularer" zu machen, ändert Bob das Programm wie folgt:
1 bob@git-workshop:~/hello_python$ vim hello.py
Bob wiederholt sein Experiment von vorhin:
1 bob@git-workshop:~/hello_python$ python3 hello.py
2 Hello, world.
3 bob@git-workshop:~/hello_python$ python3
4 Python 3.4.0 (default, Apr 11 2014, 13:05:11)
5 [GCC 4.8.2] on linux
6 Type "help", "copyright", "credits" or "license" for more information.
7 >>> import hello
8 >>> hello.hello()
9 Hello, world.
Jetzt wird "Hello, world." nur ausgegeben, wenn die Datei hello.py direkt ausgeführt wird. Wenn man sie als Modul lädt, muss man die Funktion hello() explizit aufrufen.
Bob schaut sich an, was in seinem Repository alles passiert ist:
1 bob@git-workshop:~/hello_python$ git status
2 On branch master
3 Your branch is up-to-date with 'origin/master'.
4
5 Changes not staged for commit:
6 (use "git add <file>..." to update what will be committed)
7 (use "git checkout -- <file>..." to discard changes in working directory)
8
9 modified: hello.py
10
11 Untracked files:
12 (use "git add <file>..." to include in what will be committed)
13
14 __pycache__/
15 hello.pyc
16
17 no changes added to commit (use "git add" and/or "git commit -a")
Einerseits sieht er, dass seine Änderungen an hello.py wahrgenommen wurden. Andererseits sieht er, dass ein paar Dateien bzw. Ordner hinzugekommen sind, die noch nicht von git erfasst wurden ("untracked files").
Bob möchte nicht, dass __pycache__ und hello.pyc von git aufgenommen werden. Dazu müsste er ganz einfach nichts tun. Bob möchte allerdings auch nicht, dass er ständig darauf hingewiesen wird, dass diese Dateien bzw. Ordner noch nicht überwacht werden.
Dafür legt Bob eine Datei namens .gitignore an und schreibt folgendes hinein:
Wenn Bob jetzt den Status seines Repository ansieht,
1 bob@git-workshop:~/hello_python$ git status
2 On branch master
3 Your branch is up-to-date with 'origin/master'.
4
5 Changes not staged for commit:
6 (use "git add <file>..." to update what will be committed)
7 (use "git checkout -- <file>..." to discard changes in working directory)
8
9 modified: hello.py
10
11 Untracked files:
12 (use "git add <file>..." to include in what will be committed)
13
14 .gitignore
15
16 no changes added to commit (use "git add" and/or "git commit -a")
dann bemerkt er, dass die beiden Einträge von eben verschwunden sind, aber dafür ein neuer Eintrag (.gitignore) hinzugekommen ist. „Das ist OK“, denkt sich Bob, „damit erspare ich mir in Zukunft eine Menge Nervereien.“
Jetzt möchte sich Bob den Diff seiner Änderungen ansehen:
1 bob@git-workshop:~/hello_python$ git diff
2 diff --git a/hello.py b/hello.py
3 index 13b0130..fd0d179 100755
4 --- a/hello.py
5 +++ b/hello.py
6 @@ -1,3 +1,7 @@
7 #!/usr/bin/env python3
8
9 -print("Hello, world.")
10 +def hello():
11 + print("Hello, world.")
12 +
13 +if __name__ == '__main__':
14 + hello()
Die Zeile von Alice wird gelöscht und dafür werden die Zeilen von Bob hinzugefügt.
Zufrieden mit seiner Arbeit bereitet Bob den Commit vor. Dazu fügt er die hello.py und .gitignore zu staging area hinzu:
1 bob@git-workshop:~/hello_python$ git add hello.py .gitignore
Um wirklich sicherzugehen, dass nur diese Dateien committet werden, überprüft er nochmal den Status:
Eine Datei wird geändert und eine neu hinzugefügt. Ab dafür!
Bob sieht seine Arbeit als erledigt an und bittet Alice die Änderungen zu übernehmen. Dazu teilt er ihr die Adresse seines Repository mit (/home/bob/hello_python/).
Alice sagt "Hallo, Bob!"
Alice freut sich sehr über die Nachricht von Bob und ist neugierig auf die Änderungen, die Bob an ihrem Programm gemacht hat. Zunächst fügt sie Bobs Repository als entferntes Repository zu ihrem hinzu:
1 alice@git-workshop:~/hello_python$ git remote add bob /home/bob/hello_python/
Ohne zu zögern übernimmt sie Bobs Änderungen:
1 alice@git-workshop:~/hello_python$ git pull bob
2 remote: Counting objects: 6, done.
3 remote: Compressing objects: 100% (3/3), done.
4 remote: Total 4 (delta 0), reused 0 (delta 0)
5 Unpacking objects: 100% (4/4), done.
6 From /home/bob/hello_python
7 * [new branch] master -> bob/master
8 You asked to pull from the remote 'bob', but did not specify
9 a branch. Because this is not the default configured remote
10 for your current branch, you must specify a branch on the command line.
Git teilt ihr mit, dass es das Repository zwar gäbe, aber dass Alice doch bitte deutlich sagen soll, von welchem Branch die Änderungen übernommen werden sollen. Da nur ein Branch in Bobs Repository existiert, gibt sie diesen explizit an:
Da Bobs Änderungen auf denen von Alice aufbauen, wird einfach "vorgespult" (erkennbar an "Fast-forward"). Jetzt möchte sich Alice wieder die Geschichte anschauen:
1 alice@git-workshop:~/hello_python$ git log
2 commit 100c5c12faceca13eb35518cc75b8185d25a94fe
3 Author: Bob McTest <bob@git-workshop>
4 Date: Fri Apr 10 19:57:19 2015 +0000
5
6 Macht hello.py modularer und fügt .gitignore hinzu.
7
8 commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
9 Author: Alice Testington <alice@git-workshop>
10 Date: Fri Apr 10 17:14:47 2015 +0000
11
12 Fügt Shebangzeile hinzu.
13
14 commit a9b1eee7a74fae95caa21f488a7d050f0e20d262
15 Author: Alice Testington <alice@git-workshop>
16 Date: Fri Apr 10 16:19:22 2015 +0000
17
18 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Tatsächlich wurde Bobs Commit einfach angehängt und er wird sogar als Autor aufgeführt.
Beim Anblick des Commits kommen Alice ein paar Zweifel. „Warum hat Bob in einem Commit zwei verschiedene Dateien bearbeitet? Hätte er dafür nicht zwei Commits machen können? Das wäre doch viel schöner gewesen!“ Alice liebt schöne Dinge und so dankbar sie Bob für die Verbesserung ist – für eine schöne Commit-History wäre sie noch dankbarer gewesen.
Sie teilt Bob ihre Bedenken respektvoll aber bestimmt mit und möchte, dass Bob seine Änderungen nochmal überarbeitet. Währenddessen widerruft sie Bobs Änderungen in ihrem Repository:
Damit macht Alice alle Änderungen von Bob rückgängig und bringt ihr Repository auf ihren letzten Stand. Ihre Geschichte enthält jetzt – wie zuvor – nur noch zwei Einträge.
Bob respektiert Alice' Wunsch nach einer sauberen Repositorygeschichte und widerruft auch seine Änderungen in seinem Repository. Allerdings möchte er die Änderungen nicht ganz verlieren. Er möchte, dass sein Repository auf dem vorherigen Stand ist, jedoch sollen seine Änderungen in den Dateien erhalten bleiben, aber nicht in der staging area sein. Dafür reicht folgendes:
Bob überprüft nochmal, ob auch wirklich alles so war, wie vor dem Commit:
1 bob@git-workshop:~/hello_python$ git status
2 On branch master
3 Your branch is up-to-date with 'origin/master'.
4
5 Changes not staged for commit:
6 (use "git add <file>..." to update what will be committed)
7 (use "git checkout -- <file>..." to discard changes in working directory)
8
9 modified: hello.py
10
11 Untracked files:
12 (use "git add <file>..." to include in what will be committed)
13
14 .gitignore
15
16 no changes added to commit (use "git add" and/or "git commit -a")
„Perfekt!“, denkt sich Bob, „Genau so wie ich es haben wollte. Jetzt kann ich die Dateien einzeln zur staging area hinzufügen und danach jeweils committen.“ Gedacht, getan:
1 bob@git-workshop:~/hello_python$ git add hello.py
2 bob@git-workshop:~/hello_python$ git status
3 On branch master
4 Your branch is up-to-date with 'origin/master'.
5
6 Changes to be committed:
7 (use "git reset HEAD <file>..." to unstage)
8
9 modified: hello.py
10
11 Untracked files:
12 (use "git add <file>..." to include in what will be committed)
13
14 .gitignore
15 bob@git-workshop:~/hello_python$ git commit
16 [master 6e6c421] Macht hello.py modularer.
17 1 file changed, 5 insertions(+), 1 deletion(-)
Danach kümmert er sich noch um .gitignore:
Er sagt Alice bescheid, dass er ihrem Wunsch nachgekommen ist und jetzt zwei Commits erstellt hat. Alice bedankt sich lieb bei Bob und zieht seine Änderungen:
1 alice@git-workshop:~/hello_python$ git pull bob master
2 remote: Counting objects: 5, done.
3 remote: Compressing objects: 100% (2/2), done.
4 remote: Total 3 (delta 0), reused 0 (delta 0)
5 Unpacking objects: 100% (3/3), done.
6 From /home/bob/hello_python
7 * branch master -> FETCH_HEAD
8 + 100c5c1...6450c35 master -> bob/master (forced update)
9 Updating 19e5e3e..6450c35
10 Fast-forward
11 .gitignore | 2 ++
12 hello.py | 6 +++++-
13 2 files changed, 7 insertions(+), 1 deletion(-)
14 create mode 100644 .gitignore
15 alice@git-workshop:~/hello_python$ git log
16 commit 6450c350496a4e87cd42e3749673a1eac3800ad8
17 Author: Bob McTest <bob@git-workshop>
18 Date: Fri Apr 10 20:28:32 2015 +0000
19
20 Fügt .gitignore hinzu.
21
22 commit 6e6c421cff3027537c63e9df0d56f0464d766881
23 Author: Bob McTest <bob@git-workshop>
24 Date: Fri Apr 10 20:26:39 2015 +0000
25
26 Macht hello.py modularer.
27
28 commit 19e5e3ece8832a65cfa8ed2f8c514c14617ffa8d
29 Author: Alice Testington <alice@git-workshop>
30 Date: Fri Apr 10 17:14:47 2015 +0000
31
32 Fügt Shebangzeile hinzu.
33
34 commit a9b1eee7a74fae95caa21f488a7d050f0e20d262
35 Author: Alice Testington <alice@git-workshop>
36 Date: Fri Apr 10 16:19:22 2015 +0000
37
38 Fügt hello.py hinzu, welches "Hello, world." ausgibt.
So ist's Alice recht.
Alice mag Dateien
Alice hat eine Idee: „Wie wäre es, wenn man meinem Programm einen Dateinamen übergeben könnte, der dann ausgegeben wird? Und wenn kein Dateiname übergeben wird, dann soll einfach hello() aufgerufen werden. Dank Bobs Änderungen dürfte das einfach werden.“
Auf geht's:
1 alice@git-workshop:~/hello_python$ vim hello.py
Weiterhin erstellt sie zu Testzwecken eine Datei namens hello.txt:
Dann probiert sie ihr geändertes Programm aus:
„An sich tut es, was es soll. Aber die zusätzliche Leerzeile am Ende stört mich. Vielleicht kann Bob mir dabei helfen.“ denkt sich Alice. Damit Bob das neue Feature aber überhaupt sieht, muss Alice die Änderungen erst committen:
Jetzt sagt sie Bob bescheid, der sich die Änderungen zieht:
1 bob@git-workshop:~/hello_python$ git pull origin
2 remote: Counting objects: 7, done.
3 remote: Compressing objects: 100% (3/3), done.
4 remote: Total 3 (delta 0), reused 0 (delta 0)
5 Unpacking objects: 100% (3/3), done.
6 From /home/alice/hello_python
7 19e5e3e..972cf5c master -> origin/master
8 Updating 6450c35..972cf5c
9 Fast-forward
10 hello.py | 10 +++++++++-
11 1 file changed, 9 insertions(+), 1 deletion(-)
Bevor Bob aber seine pythonische Weisheit auf Alice' Programm anwenden kann, kommt Alice eine neue Idee. „Wie wäre es, wenn das Programm nicht "Hello, world." ausgäbe, sondern "Hello, alice." oder "Hello, bob." – je nachdem, wie der Benutzername lautet?“ Im Internet hat Alice auch schon die notwendigen Zeilen gefunden, die sie braucht. Außerdem hat Alice im Internet auch von den tollen Möglichkeiten zum Branching gelesen. Das will sie jetzt ausprobieren.
Sie schaut sich erstmal an, welche Branches gerade vorhanden sind:
Nur ein Branch namens master. Für ihre Benutzernamenerweiterung legt sie einen neuen Branch namens gibt_benutzername_aus an:
Jetzt existieren zwei Branches. Sie wechselt zum neu erstellten Branch:
Der Stern gibt also an, auf welchem Branch sich Alice gerade befindet.
In diesem Branch ändert sie hello.py und schaut sich danach die Änderungen an:
1 alice@git-workshop:~/hello_python$ vim hello.py
2 alice@git-workshop:~/hello_python$ git diff
3 diff --git a/hello.py b/hello.py
4 index 570eac1..d11424c 100755
5 --- a/hello.py
6 +++ b/hello.py
7 @@ -1,9 +1,11 @@
8 #!/usr/bin/env python3
9
10 import sys
11 +import getpass
12
13 def hello():
14 - print("Hello, world.")
15 + username = getpass.getuser()
16 + print("Hello, %s." % username)
17
18 if __name__ == '__main__':
19 if len(sys.argv) == 2:
Natürlich probiert sie ihr Programm gleich aus:
„Bravo!“, denkt sich Alice. Jetzt muss sie ihre Änderungen nur zur staging area hinzufügen und committen:
Dieser Commit ist aber nur im Branch "gibt_benutzername_aus" enthalten. Der master-Branch kennt die Änderungen (noch) nicht. Dies möchte Alice etwas genauer inspizieren:
1 alice@git-workshop:~/hello_python$ git branch
2 * gibt_benutzername_aus
3 master
4 alice@git-workshop:~/hello_python$ git log --oneline
5 7db7d7e Gibt den Benutzernamen beim Aufruf von hello() aus.
6 972cf5c hello.py kann jetzt auch Dateien lesen.
7 6450c35 Fügt .gitignore hinzu.
8 6e6c421 Macht hello.py modularer.
9 19e5e3e Fügt Shebangzeile hinzu.
10 a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
11 alice@git-workshop:~/hello_python$ git checkout master
12 Switched to branch 'master'
13 alice@git-workshop:~/hello_python$ git branch
14 gibt_benutzername_aus
15 * master
16 alice@git-workshop:~/hello_python$ git log --oneline
17 972cf5c hello.py kann jetzt auch Dateien lesen.
18 6450c35 Fügt .gitignore hinzu.
19 6e6c421 Macht hello.py modularer.
20 19e5e3e Fügt Shebangzeile hinzu.
21 a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Jetzt hat Alice den Überblick über ihre Branches und die darin enthaltenen Commits. Aus dem master-Branch heraus übernimmt sie den Commit aus dem gibt_benutzername_aus-Branch:
1 alice@git-workshop:~/hello_python$ git branch
2 gibt_benutzername_aus
3 * master
4 alice@git-workshop:~/hello_python$ git merge gibt_benutzername_aus
5 Updating 972cf5c..7db7d7e
6 Fast-forward
7 hello.py | 4 +++-
8 1 file changed, 3 insertions(+), 1 deletion(-)
9 alice@git-workshop:~/hello_python$ git log --oneline
10 7db7d7e Gibt den Benutzernamen beim Aufruf von hello() aus.
11 972cf5c hello.py kann jetzt auch Dateien lesen.
12 6450c35 Fügt .gitignore hinzu.
13 6e6c421 Macht hello.py modularer.
14 19e5e3e Fügt Shebangzeile hinzu.
15 a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Jetzt enthält auch der master-Branch den Commit 7db7d7e. Sie freut sich, dass man die SHA1-Werte auch verkürzt ansehen und benutzen kann.
Währenddessen bei Bob
Bob konnte sein anderes Projekt glücklicherweise zur Deadline fertigstellen und wendet sich wieder Alice' Programmiereifer zu. Beim Durchsehen bemerkt er ein paar Verbesserungsmöglichkeiten:
1 bob@git-workshop:~/hello_python$ vim hello.py
1 #!/usr/bin/env python3
2
3 import sys
4
5 def hello():
6 print("Hello, world.")
7
8 if __name__ == '__main__':
9 if len(sys.argv) == 2:
10 try:
11 filename = sys.argv[1]
12 with open(filename) as f:
13 msg = f.read().strip()
14 print(msg)
15 except:
16 print("Fehler: konnte %s nicht öffnen!" % filename)
17 else:
18 hello()
Wohlgemerkt weiß Bob noch nichts von Alice' Benutzernamenverbesserung. Sein Programm funktioniert aber ganz gut:
1 bob@git-workshop:~/hello_python$ ./hello.py
2 Hello, world.
3 bob@git-workshop:~/hello_python$ ./hello.py hello.txt
4 Fehler: konnte hello.txt nicht öffnen!
5 bob@git-workshop:~/hello_python$ echo "Dies ist eine Datei." > hello.txt
6 bob@git-workshop:~/hello_python$ ./hello.py hello.txt
7 Dies ist eine Datei.
Beim Überprüfen des Status' fällt ihm auf, dass hello.txt jetzt auch von git bemerkt wird:
1 bob@git-workshop:~/hello_python$ git status
2 On branch master
3 Your branch is up-to-date with 'origin/master'.
4
5 Changes not staged for commit:
6 (use "git add <file>..." to update what will be committed)
7 (use "git checkout -- <file>..." to discard changes in working directory)
8
9 modified: hello.py
10
11 Untracked files:
12 (use "git add <file>..." to include in what will be committed)
13
14 hello.txt
15
16 no changes added to commit (use "git add" and/or "git commit -a")
17 bob@git-workshop:~/hello_python$ echo '*.txt' >> .gitignore
18 bob@git-workshop:~/hello_python$ git status
19 On branch master
20 Your branch is up-to-date with 'origin/master'.
21
22 Changes not staged for commit:
23 (use "git add <file>..." to update what will be committed)
24 (use "git checkout -- <file>..." to discard changes in working directory)
25
26 modified: .gitignore
27 modified: hello.py
28
29 no changes added to commit (use "git add" and/or "git commit -a")
Da Bob weiß wie wichtig Alice' ihre Commits sind, legt er für jede Datei einen Commit an:
1 bob@git-workshop:~/hello_python$ git add hello.py
2 bob@git-workshop:~/hello_python$ git commit
3 [master d79b3aa] Verbessert hello.py.
4 1 file changed, 7 insertions(+), 4 deletions(-)
5 bob@git-workshop:~/hello_python$ git add .gitignore
6 bob@git-workshop:~/hello_python$ git commit
7 [master 8615c04] Alle Dateien mit *.txt werden von jetzt an ignoriert.
8 1 file changed, 1 insertion(+)
Bob sagt Alice bescheid, dass er ihr Programm verbessert hat und sie seine Änderungen ziehen kann.
Zurück zu Alice
Alice freut sich sehr über die Nachricht von Bob und versucht seine Commits in ihr Repository einzupflegen:
Es öffnet sich ihr Lieblingseditor und bittet sie eine commit message einzugeben. Es steht schon folgendes drin:
1 Merge branch 'master' of /home/bob/hello_python
„Wird schon seine Richtigkeit haben.“, denkt sich Alice. Sie speicherte und schloss die Datei. Neugierig wie jetzt wohl ihre Repositorygeschichte aussehen würde, probiert sie folgendes aus:
1 alice@git-workshop:~/hello_python$ git log --oneline --graph
2 * 5621ae2 Merge branch 'master' of /home/bob/hello_python
3 |\
4 | * 8615c04 Alle Dateien mit *.txt werden von jetzt an ignoriert.
5 | * d79b3aa Verbessert hello.py.
6 * | 7db7d7e Gibt den Benutzernamen beim Aufruf von hello() aus.
7 |/
8 * 972cf5c hello.py kann jetzt auch Dateien lesen.
9 * 6450c35 Fügt .gitignore hinzu.
10 * 6e6c421 Macht hello.py modularer.
11 * 19e5e3e Fügt Shebangzeile hinzu.
12 * a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
„Ahja“, denkt sich Alice, „jetzt kann man genau sehen, wo sich unsere Geschichte verzweigte und wo sie wieder zusammengeführt wurde.“ Jedoch behagte es ihr nicht recht. Könnte man die Commits von Bob nicht so einpflegen, dass sie alle nacheinander angeordnet würden?
Zunächst verwirft sie die eben gezogenen Commits von Bob und spult die Geschichte auf Alice' letzten Stand zurück:
1 alice@git-workshop:~/hello_python$ git reset --hard 7db7d7e
2 HEAD is now at 7db7d7e Gibt den Benutzernamen beim Aufruf von hello() aus.
3 alice@git-workshop:~/hello_python$ git log --oneline --graph
4 * 7db7d7e Gibt den Benutzernamen beim Aufruf von hello() aus.
5 * 972cf5c hello.py kann jetzt auch Dateien lesen.
6 * 6450c35 Fügt .gitignore hinzu.
7 * 6e6c421 Macht hello.py modularer.
8 * 19e5e3e Fügt Shebangzeile hinzu.
9 * a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
Dann wendet sie die Option --rebase beim Ziehen von Bobs Commits an und schaut sich wieder die Geschichte mit dazugehörigem Graphen an:
1 alice@git-workshop:~/hello_python$ git pull --rebase bob master
2 From /home/bob/hello_python
3 * branch master -> FETCH_HEAD
4 First, rewinding head to replay your work on top of it...
5 Applying: Gibt den Benutzernamen beim Aufruf von hello() aus.
6 alice@git-workshop:~/hello_python$ git log --oneline --graph
7 * ed605ec Gibt den Benutzernamen beim Aufruf von hello() aus.
8 * 8615c04 Alle Dateien mit *.txt werden von jetzt an ignoriert.
9 * d79b3aa Verbessert hello.py.
10 * 972cf5c hello.py kann jetzt auch Dateien lesen.
11 * 6450c35 Fügt .gitignore hinzu.
12 * 6e6c421 Macht hello.py modularer.
13 * 19e5e3e Fügt Shebangzeile hinzu.
14 * a9b1eee Fügt hello.py hinzu, welches "Hello, world." ausgibt.
So ist's Alice recht.
Cheatsheet
Ein Cheatsheet mit den gängigsten Befehlen findet ihr unter git-cheatsheet.pdf.
Eigenarbeit
Finde dich in einem Team mit insgesamt maximal 3 Mitgliedern zusammen.
Entwickelt zusammen ein Trainingsprogramm für arithmetische Aufgaben (Grundrechenarten). Dabei sollen nur ganzzahlige Operanden vorkommen. Dem Nutzer soll es ermöglicht werden, die Anzahl und Art der gestellten Aufgaben zu bestimmen (sprich: wie viele Aufgaben und was für Grundrechenarten). Dabei soll die Anzahl der richtigen Ergebnisse gezählt und dem Nutzer am Ende eine kurze Statistik präsentiert werden.
Falls Fragen oder Unklarheiten aufkommen, dann versucht im Team einen Konsens über die eurer Meinung nach sinnvollste Lösung zu finden und fragt erst dann. Nutzt git und das interne GitLab für die Zusammenarbeit. Die Wahl der Programmiersprache und der Benutzerschnittstelle sind euch freigestellt.
Ich wäre sehr erfreut, wenn ein Teammitglied das Programm und die Zusammenarbeit im Team am Ende vorstellt.
Feedback
Bevor ihr geht, beantwortet bitte noch schnell diese 4+1 Fragen. Danke!