Symfony und Doctrine: Entity- und Repository-Klassen nachträglich erstellen

Wer Symfony für ein bereits bestehendes Projekt nutzen will, steht vor dem Problem, dass es sehr mühsam (und erst recht fehleranfällig) sein kann, händisch die Entity- und Repository-Klassen nachträglich zu erstellen.

Um die Entity- und Repository-Klassen aus bestehenden Tabellen zu erzeugen, können Sie den folgenden Befehl verwenden:

php bin/console doctrine:mapping:import "App\Entity" annotation --path=src/Entity

Dieser Befehl wird die Entities aus den Tabellen Ihrer Datenbank im Annotation-Format im Verzeichnis app/src/Entity erzeugen.

Es kann durchaus der Fall sein, dass doctrine bestimmte Maßnahmen fordert. Ich musste zum Beispiel mehrmals nachträglich in meinen Tabellen (gerade in den unbedeutenden) Primärschlüssel erzeugen. Und der spezielle MySQL-Datentyp ENUM muss durch den allgemeineren Typ SET ersetzt werden. Aber diese Anpassungen sollten gefahrlos vorzunehmen sein.

Sie müssen dann die @ORM\Entity-Annotation in jeder Entity-Klasse ändern, um das entsprechende Repository anzugeben. Zum Beispiel:

@ORM\Entity (repositoryClass="App\Repository\UserRepository")

Sie können dann den folgenden Befehl verwenden, um die Entity-Klassen zu aktualisieren:

php bin/console make:entity --regenerate

Dann tauchen auch aufeinmal auch die getter- und setter-Methoden auf.

Beachten Sie, dass der Befehl doctrine:mapping:import von Doctrine im Jahr 2019 als veraltet markiert wurde und es keinen Ersatz dafür gibt. Stattdessen können Sie den Befehl make:entity vom Symfony Maker Bundle verwenden, um Ihnen bei der Erstellung des Codes Ihrer Doctrine-Entities zu helfen. Dieser Befehl erfordert jedoch eine manuelle Überwachung, da er keine Entities aus bestehenden Datenbanken erzeugt.

Nützliche Prompts für ChatGPT

Die richtige Aufforderung („Prompt“) ist der wichtigste Faktor im Umgang mit ChatGPT, da sie die Art und Weise beeinflusst, wie der Chatbot reagiert und antwortet. Ein gut formulierter Prompt kann die Genauigkeit und Relevanz der Antworten von ChatGPT verbessern und gleichzeitig die Wahrscheinlichkeit von unerwünschten oder ungenauen Antworten verringern. Es ist wichtig, eine klare und präzise Aufforderung zu verwenden, um sicherzustellen, dass ChatGPT versteht, was von ihm erwartet wird, und dass seine Antwort auf die spezifische Frage oder das spezifische Thema zugeschnitten ist. Eine schlecht formulierte Aufforderung kann hingegen zu unklaren und verwirrenden Antworten führen, die das Gespräch erschweren oder unnötig in die Länge ziehen.

Hier einige Beispiele, wie ich aktuell die KI bediene.

Bessere Texte in Dialogform gemeinsam mit der KI entwerfen

Kannst du meine Aufforderung verbessern, indem du mir Fragen stellst? Wenn du bereit bist, schreib die verbesserte Aufforderung und stell mir neue Fragen, nachdem ich deine vorherigen Fragen beantwortet habe. Ist das für dich okay?

Wie kreativ darf es sein?

Berücksichtige bitte ab jetzt den „Kfaktor“. Wenn der Kfaktor 1 ist, werden deine Antworten einfach und nicht sehr kreativ sein. Wenn der Kfaktor 10 ist, ist das die Höchstgrenze und du wirst sehr kreativ antworten. Verstehst du das?

Eine Prise Humor, bitte schön!

Berücksichtige bitte ab jetzt den „Hfaktor“. Wenn der Hfaktor 1 ist, werden deine Antworten trocken, journalistisch und humorlos sein. Wenn der Hfaktor 10 ist, ist das die Höchstgrenze und du wirst sehr lustig und humorvoll antworten. Verstehst du das?

Die Autorenrolle finden

Schreibe bitte wie ein erfahrener Werbetexter/Journalist/Arzt/Politiker.

Ein guter Bewerbungstext, oder?

Eine Anleitung zum Lernen erstellen

Ich möchte ein PHP-Programmierer werden. Schreibe mir einen einfachen Schritt-für-Schritt-Plan, der mir beim Lernen hilft. Fange mit den wichtigsten Punkten an und berücksichtige bitte das 80-20-Prinzip. Nutze Markdown Formatierungen für Überschriften und hebe wichtige Punkte fett hervor.

Ich bin PHP-Programmierer, und diese Anleitung (die man in weiteren Schritten auch zu einem kompletten Trainings-Handbuch erweitern könnte) ist wirklich gut.

Mache die KI zu deinem Assistenten

Jetzt wird es noch interessanter. Lassen wir doch die KI mal eine komplexe Aufgabe erledigen, während wir an der Playstation sitzen.

Ich benötige eine Marktstudie über den Verkauf von Induktionsöfen in Deutschland. Bestimme bitte alle Schritte, um sie zu realisieren, und setze sie dann selbstständig ohne meine Hilfe um.

Kleiner Tipp: Wenn der Text zwischendurch abreist, einfach kurz von der Playstation aufstehen und „weiter bitte“ eintippen.

Und jetzt noch ein kleiner Witz

Erzähl mir einen Witz, der so anfängt: Darth Vader, der Papst und Greta Thunberg betreten eine Bar, da sagt Darth Vader …

Ergebnis:

Darth Vader: Ich spüre eine starke Macht in diesem Raum... ach nein, das ist ja nur Greta Thunberg, die ihr Handy auflädt.

Nach ca. 20 Versuchen wurde es dann wirklich etwas lustig. Ich bin positiv überrascht.

Darth Vader, der Papst und Greta Thunberg betreten eine Bar. Der Barkeeper schaut sie an und sagt: „Was kann ich euch anbieten?“ Der Papst antwortet: „Ich nehme ein Glas Wasser, bitte.“ Greta sagt: „Ich nehme ein Glas Saft, aber bitte aus biologischem Anbau.“ Und Darth Vader sagt: „Ich nehme ein Glas Milch.“ Der Barkeeper schaut ihn überrascht an und fragt: „Milch? Wirklich?“ Darth Vader antwortet: „Ja, ich muss meine dunkle Seite ein bisschen aufhellen.“

Stack: Ubuntu, Webmin, nginx, PostgreSQL, Samba, Symfony

Quellen:

https://ubuntu.com/

https://www.nginx.com/

https://symfony.com/

https://www.postgresql.org/

Ubuntu

Mehr Informationen:

https://ubuntu.com/tutorials/install-ubuntu-desktop#1-overview

SSH installieren

sudo apt install openssh-server
sudo systemctl status ssh
sudo systemctl enable ssh
sudo systemctl start ssh
sudo reboot

Einwahl über SSH-Client, wie bspw. Putty

Mehr Informationen:

https://www.ionos.de/digitalguide/server/konfiguration/ubuntu-ssh/

IPv6 ausschalten

sudo nano /etc/default/grub
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash ipv6.disable=1"
GRUB_CMDLINE_LINUX="ipv6.disable=1"
sudo update-grub
sudo reboot

Mehr Informationen:

https://itsfoss.com/disable-ipv6-ubuntu-linux/

Shell pimpen

sudo apt-get install trash-cli # Papierkorb
sudo cp /etc/bash.bashrc /etc/bash.bashrc.bak
sudo nano /etc/bash.bashrc
alias +='pushd .'
alias ..='cd ..'
alias ...='cd ../..'
alias dir='ls -la  --color=auto'
alias d='ls -la  --color=auto'
alias gzcat='gunzip -c'
alias l='ls -alF'
alias la='ls -la'
alias ll='ls -la'
alias ls='/bin/ls $LS_OPTIONS'
alias ls-l='ls -l'
alias md='mkdir -p'
alias o='less'
alias rd='rmdir'
alias rehash='hash -r'
alias rm='rm -i'
alias unzip='tar xfvz'
alias which='type -p'
alias zip='tar cfvz'
alias sudo='sudo '
alias del='trash -rf'
sudo nano ~/.bashrc # ein kürzerer Prompt
GREEN="\[$(tput setaf 2)\]"
RESET="\[$(tput sgr0)\]"
PS1="${GREEN}$${RESET}"

Mehr Informationen:

https://1manfactory.com/pimp-my-shell-eine-vernuenftige-arbeitsumgebung-fuer-linux/

ein Zusatz-Admin zur Sicherheit

sudo adduser <NUTZER>
sudo adduser <NUTZER> sudo

Webmin

sudo apt update
curl -fsSL https://download.webmin.com/jcameron-key.asc | sudo gpg --dearmor -o /usr/share/keyrings/webmin.gpg
sudo nano /etc/apt/sources.list
deb [signed-by=/usr/share/keyrings/webmin.gpg] http://download.webmin.com/download/repository sarge contrib
sudo apt update
sudo apt install webmin
# Browser: http://<HOST>:10000

Mehr Informationen:

https://www.digitalocean.com/community/tutorials/how-to-install-webmin-on-ubuntu-22-04

nginx

sudo apt update
sudo apt install nginx
sudo systemctl status nginx
# Browser: http://<HOST>
sudo systemctl stop nginx # Stoppen
sudo systemctl start nginx # Starten
sudo systemctl restart nginx # Neustart
sudo systemctl reload nginx # sanfter Neustart nach Neu/Re-Konfiguration
sudo systemctl disable nginx # Autostart (Default) verhindern
sudo systemctl enable nginx # Autostart wieder ermöglichen

Rechte für /var/www/html

sudo chown -R www-data: /var/www/html/
sudo find /var/www/html -type f -exec chmod 664 {} + -o -type d -exec chmod 775 {} +
sudo usermod -a -G www-data $USER
exit # Neueinwahl nötig

PHP für nginx

sudo apt-get install php8.1-fpm
sudo systemctl status php8.1-fpm # läuft der PHP-Service?
sudo nano /etc/nginx/sites-available/default

Folgendes muss angepasst werden:

  • index.php zur Indexliste hinzufügen (Zeile 8)
  • Entkommentieren der Zeilen 17, 18, 21, 24, 28, 29 und 30
server {
  # Example PHP Nginx FPM config file
  listen 80 default_server;
  listen [::]:80 default_server;
  root /var/www/html;

  # Add index.php to setup Nginx, PHP & PHP-FPM config
  index index.php index.html index.htm index.nginx-debian.html;

  server_name _;

  location / {
    try_files $uri $uri/ =404;
  }

  # pass PHP scripts on Nginx to FastCGI (PHP-FPM) server
  location ~ \.php$ {
    include snippets/fastcgi-php.conf;

    # Nginx php-fpm sock config:
    fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    # Nginx php-cgi config :
    # Nginx PHP fastcgi_pass 127.0.0.1:9000;
  }

  # deny access to Apache .htaccess on Nginx with PHP, 
  # if Apache and Nginx document roots concur
  location ~ /\.ht {
    deny all;
  }
} # End of PHP FPM Nginx config example
sudo nginx -t # um die Änderungen an der Konfiguration zu testen
sudo systemctl restart nginx # Neustart des Servers

Mehr Informationen:

https://1manfactory.com/nginx-ubuntu-php-fpm/

PHPINFO

sudo echo "<?php phpinfo(); ?>" >> /var/www/html/info.php
# Browser http://<HOST>/info.php

nginx-Modul für Webmin

Webmin -> Webmin Configuration -> Webmin Modules
Install from “From HTTP or FTP URL”
Quelle: https://github.com/Sumarious/nginx-webmin/raw/master/nginx.wbm.gz

Mehr Informationen:

https://github.com/Sumarious/nginx-webmin

https://www.digitalocean.com/community/tutorials/how-to-install-nginx-on-ubuntu-20-04

Composer

sudo apt update
sudo apt install php-cli unzip # benötigt
cd ~
curl -sS https://getcomposer.org/installer -o /tmp/composer-setup.php
HASH=`curl -sS https://composer.github.io/installer.sig`
echo $HASH
php -r "if (hash_file('SHA384', '/tmp/composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
sudo php /tmp/composer-setup.php --install-dir=/usr/local/bin --filename=composer
composer

Mehr Informationen:

https://www.digitalocean.com/community/tutorials/how-to-install-and-use-composer-on-ubuntu-22-04

PostgreSQL

sudo apt update
sudo apt install postgresql postgresql-contrib
sudo systemctl start postgresql.service
sudo systemctl status postgresql

Mehr Informationen:

https://www.digitalocean.com/community/tutorials/how-to-install-and-use-postgresql-on-ubuntu-20-04

PostgreSQL in Webmin

Webmin -> Refresh Modules
Servers -> PostgreSQL Database Server

HeidiSQL für PostgreSQL

WICHTIG: IP6 muss deaktiviert sein (siehe oben)

sudo nano /etc/postgresql/14/main/postgresql.conf
listen_addresses = '*'
sudo nano /etc/postgresql/14/main/pg_hba.conf
# IPv4 local connections:
#host    all      all             127.0.0.1/32		scram-sha-256
host     all       all            0.0.0.0/0		scram-sha-256
sudo service postgresql restart

Da IP6 jetzt deaktiviert ist, muss noch eine Einstellung für nginx dringend angepasst werden:

sudo nano /etc/nginx/sites-available/default
#listen [::]:80 default_server; dieser Eintrag muss deaktiviert sein, wenn kein IP6
sudo systemctl restart nginx # nginx neu starten

neuer User für PostgreSQL

Webmin -> PostgreSQL -> PostgreSQL Users -> Create a new user

Samba

sudo apt-get install samba
sudo cp /etc/samba/smb.conf /etc/samba/smb.conf_backup # Kopie schadet nie
systemctl status smbd # Status prüfen
sudo nano /etc/samba/smb.conf
[www]
  comment = Web Root Dir
  path = /var/www/html
  valid users = @www-data
  browseable = yes
  public = no
  writable = yes
  printable = no
  create mode = 0644
  directory mode = 0775
  force group = www-data
  force user = www-data
sudo usermod -aG www-data $USER
sudo smbpasswd -a $USER # für jeden Nutzer notwendig, der Samba nutzen soll
sudo service smbd restart
systemctl status smbd
sudo smbstatus --shares # zeigt aktive Verbindungen

In der Windows-Kommandozeile eine Verbindung herstellen:

net use X: \\<HOST>\www /user:<USER> <PASSWORD>

Symfony

Symfony-cli Binary installieren

sudo apt-get install php-xml # wird noch benötigt
cd ~
curl -1sLf 'https://dl.cloudsmith.io/public/symfony/stable/setup.deb.sh' | sudo -E bash
sudo apt install symfony-cli

ein neues Symfony-Projekt anlegen

sudo chown -R www-data:www-data /var/www/html/
sudo find /var/www/html/ -type d -exec chmod 775 {} \;
sudo find /var/www/html/ -type f -exec chmod 664 {} \;
sudo find /var/www/html/ -type d -exec chmod g+s {} \;
cd /var/www/html/
symfony new --webapp testprojekt
cd testprojekt/
composer require --dev symfony/profiler-pack
symfony server:start -d # Symfony Server starten

Aufruf über Symfony Server

Aufruf über nginx

Wie synchronisiere ich ein Projekt mit einem schon existierendem Repository in GitHub?

Wer erst nachträglich auf die Idee kommt, den eigenen Entwicklungsserver mit einem Produktionsserver per Git und GitHub zu synchronisieren, steckt vor dem Problem, wie man eine Verbindung zu GitHub herstellt und einen erstmaligen Abgleich der Dateien herstellt. Danach kann und sollte ein Deployment dann nur noch per git erfolgen.

Wie immer ist es einfach, wenn man weiß, wie es geht, oder welche Fragen man stellen muss.

Problembeschreibung

Problem: ein Projekt (auf Produktion), das bisher nur mit FTP deployt wurde, soll nachträglich nur noch mit einem GitHub Repository ohne FTP synchronisiert werden.

SSH-Schlüssel bei GitHub hinterlegen

Da es sich aller Wahrscheinlichkeit nach um ein privates Projekt handelt, muss sich der Produktionsserver (=Ziel) gegenüber GitHub authentifizieren. Dazu muss man einen öffentlichen Schlüssel erzeugen und bei GitHub hinterlegen. Erklärt habe ich das bereits hier (für Windows) und hier (für Linux).

ls -al ~/.ssh # testen, ob schon Keys vorhanden sind
mkdir ~/.ssh # wenn nicht, Ordner anlegen
cd ~/.ssh
ssh-keygen -t rsa -b 4096 -C "<BESCHREIBUNG>"
ls -la

Danach muss git wissen, wo es die SSH-Schlüssel findet.

nano ~/.ssh/config

Der einfachste und funktionsfähige Inhalt wäre folgender:

# Private github account: 1manfactory
Host github-private
HostName github.com
IdentityFile ~/.ssh/id_rsa
IdentitiesOnly yes

Wir müssen GitHub als bekannten Host hinzufügen:

ssh-keyscan github.com >> ~/.ssh/known_hosts

Ich authentifiziere mich als git@github-private bei GitHub.

ssh -T git@github-private

Das git Repository auf Produktion anlegen und mit dem remote Repository verbinden

Navigieren Sie zum Verzeichnis Ihres lokalen Projekts auf dem Produktionsserver und führen Sie folgende Befehle aus.

cd <PROJEKTVERZEICHNIS>
git init
git config -l
git remote add origin git@github-private:<USER>/<REPOSITORY>.git
git remote -v
git pull origin main
git checkout main -f
git branch --set-upstream-to origin/main

Ich erkläre die einzelnen Schritte.

git init ist ein Befehl, der ein neues Git-Repository in einem lokalen Verzeichnis erstellt. Er legt einen versteckten Ordner namens .git an, der die Repository-Daten enthält. Er macht das Verzeichnis bereit für die Versionskontrolle mit Git.

git config -l ist ein Befehl, der alle Git-Konfigurationsoptionen anzeigt, die für das aktuelle Repository oder den aktuellen Benutzer gesetzt sind. Er liest die Werte aus den Dateien .git/config, ~/.gitconfig und /etc/gitconfig. Er kann nützlich sein, um die Einstellungen zu überprüfen oder zu ändern.

git remote add origin ist ein Befehl, der einen Remote-Namen namens origin zu einem lokalen Repository hinzufügt. Er verbindet das lokale Repository mit einem Remote-Repository, das an den Befehl angehängt wird. Er ermöglicht das Hochladen und Herunterladen von Änderungen zwischen den Repositories.

git remote -v zeigt die Liste der Remote-Namen und ihre URLs an. Er hilft zu überprüfen, ob die Remote-Verbindungen korrekt sind.

git pull origin main ist ein Befehl, der den lokalen Branch main mit dem Remote-Branch main von origin aktualisiert. Er lädt zuerst alle Änderungen vom Remote-Repository herunter und führt dann einen Merge oder einen Rebase aus. Er bringt das lokale Repository auf den neuesten Stand.

git branch --set-upstream-to origin/main ist ein Befehl, der den aktuellen lokalen Branch mit dem Remote-Branch main von origin verknüpft. Er legt fest, welcher Remote-Branch als Standard für das Pushen und Pullen verwendet wird. Er erleichtert die Synchronisation zwischen den Branches.

Als Ergebnis sollte jetzt der Produktionsserver auf demselben Stand sein wie das GitHub-Repository (und damit auch wie der Entwicklungsserver).

Das zukünftige Deployment

Ab jetzt können wir den Weg über git pull oder git fetch && git merge gehen, um Änderungen aus dem remote Repository bei GitHub zu übernehmen.

Die schnelle Methode ‘git pull’

git pull

git pull ist ein Befehl, der den aktuellen lokalen Branch mit dem entsprechenden Remote-Branch aktualisiert. Er entspricht einem git fetch gefolgt von einem git merge oder einem git rebase. Er benötigt einen Remote-Namen und einen Branch-Namen oder eine Verknüpfung zwischen den Branches.

Die vorsichtigere Methode mit ‘get fetch’

git fetch origin
git log origin/main ^main
git diff main origin/main
git merge

git fetch origin ist ein Befehl, der alle Änderungen vom Remote-Repository origin herunterlädt. Er aktualisiert die lokalen Referenzen zu den Remote-Branches, aber nicht die lokalen Branches. Er ermöglicht es, die Differenzen zwischen den Branches zu sehen oder einen Merge oder einen Rebase auszuführen.

git log origin/main ^main ist ein Befehl, der die Commit-Historie vom Remote-Branch origin/main anzeigt, die nicht im lokalen Branch main enthalten ist. Er hilft, zu sehen, welche Änderungen noch nicht synchronisiert sind.

Der Befehl git diff main origin/main zeigt die Unterschiede zwischen dem lokalen Zweig main und dem entfernten Zweig origin/main an². Er kann verwendet werden, um zu sehen, welche Änderungen Sie noch nicht mit dem entfernten Repository synchronisiert haben.

Git und GitHub für Windows mit Sourcetree, Teil 3: Branches, Pull Requests und Fetch

Das Thema Branches ist sehr wichtig für die Arbeit mit GitHub. Im Grunde kommt man nicht an ihnen vorbei, spätestens wenn man nicht mehr allein an einem Projekt arbeitet.

Was sind Branches?

In Git sind Branches (dt. Zweige) Versionen des Projekts, die sich inhaltlich voneinander unterscheiden und dabei gleichzeitig parallel existieren können.

Branches sind eine wichtige Funktion in Git, da sie es Entwicklern ermöglichen, verschiedene Ideen oder Experimente gleichzeitig auszuprobieren, ohne die ursprüngliche Version des Projekts zu beeinträchtigen. Zum Beispiel kann man einen neuen Branch erstellen, um eine neue Funktion auszuprobieren, während der Haupt-Branch stabil bleibt. Wenn die neue Funktion erfolgreich getestet wurde, kann sie in den Haupt-Branch übernommen („gemerged“) werden.

Git ermöglicht auch, zwischen Branches zu wechseln und zu arbeiten, wodurch Entwickler effizienter arbeiten können, ohne dass sie separate Arbeitskopien erstellen müssen.

Das Wechseln zwischen Branches ist einfach und schnell, sodass Entwickler problemlos zwischen verschiedenen Versionen ihres Projekts navigieren können.

Wir legen einen neuen Branch an

  1. Öffnen Sie Ihr Repository in Sourcetree.
  2. Klicken Sie auf den Button „Branch“ in der oberen Menüleiste.
  3. Klicken Sie auf den Reiter „New Branch“ im neuen Fenster.
  4. Geben Sie einen Namen für Ihren neuen Branch ein und wählen Sie den Branch aus, von dem Sie den neuen Branch ableiten möchten. Standardmäßig wird der neue Branch von dem aktuell ausgewählten Branch (hier: main) abgeleitet.
  5. Klicken Sie auf den Button „Create Branch“.

Ich nenne den neuen Branch „new_feature“. Allerdings werden wir kein neues Feature einführen, sondern lediglich an der schon bekannten Datei „README.md“ etwas ändern.

Fortan wollen wir also im „new_feature“-Branch arbeiten. In unserem Repository wird aber weiterhin das Projekt in seiner ursprünglichen Version verbleiben und parallel existieren.

Mit einem Doppelklick auf der linken Seite auf den Namen der Branch springen wir zwischen „main“ und „new_feature“ hin und her.

Wir fügen jetzt in unserer bekannten Datei „README.md“ eine neue Zeile, genauer eine neue Überschrift hinzu. Außerdem ist mir gerade aufgefallen, dass ich „turotial“ statt „tutorial“ geschrieben habe. Das wird auch korrigiert.

Nach dem Speichern wechseln wir wieder zu Sourcetree und sehen nach wenigen Sekunden Wartezeit erwartungsgemäß unsere Datei wieder im Status „Unstaged“. Rechts oben erkennen wir die vorgenommenen Änderungen.

Wie bereits durchexerziert, schieben wir die Datei in den „Staged“ Bereich und führen anschließend ein Commit durch.

Nun sehen wir einen veränderte History-Bereich:

In dem neuen Branch wurden die Änderungen übernommen. Klicken wir nun wieder auf den ursprünglichen Branch, sehen wir noch den alten, ursprünglichen Stand der Datei.

Jetzt sorgen wir mit „Push“ dafür, dass die veränderte Datei bei GitHub landet. Im aufgehenden Fenster nehmen Sie bitte folgende Anpassungen vor:

Und wieder ist eine kleine Änderung im History-Bereich zu sehen.

Schauen wir jetzt in GitHub nach, was passiert ist. Sie wechseln jetzt in den Status, und damit in die Perspektive, des Administrators. Sie sind also jetzt eine andere Person als die, die die Änderungen vorgenommen hat.

GitHub weist uns darauf hin, dass ein neuer Branch angelegt worden ist und dass in diesen Branch neue Dateien (in unserem Falle nur eine) gepusht wurden.

Da wir uns aber noch im Hauptbranch „main“ befinden, sind die Änderungen noch nicht zu sehen – was ja Sinn der Aktion war. Denn noch wissen wir nicht, ob die Änderungen fehlerfrei sind und bei den anderen (spekulativen) Administratoren im Projekt Akzeptanz finden.

Wir zeigen jetzt den Branch „new_feature“ an. Dazu drücken wir den Dropdown-Button mit der Aufschrift „main“ und wechseln auf „new_feature“

Wir sehen jetzt den neuen Branch „new_feature“

Dieser Branch hat jetzt (auch wieder wie erwartet) unsere Änderungen und befindet sich „1 commit ahead of main“. Was bedeutet das?

Der aktuelle Branch hat einen Commit mehr als der Branch „main“. Die Änderungen im neuen Feature-Branch wurden noch nicht in den „main“-Branch übertragen (=gemerged). Auch das ist ein schlüssiges, gewolltes Verhalten von git bzw. GitHub.

Compare & pull request

Sehen Sie den Button mit der Aufschrift “Compare & pull request”?

„Compare“ und „Pull Request“ sind Funktionen in Git und GitHub, die es Entwicklern ermöglichen, Änderungen an einem Repository vorzuschlagen und sie in den Hauptzweig (z.B. „main“ oder „master“) zu integrieren.

„Compare” ermöglicht es, den Unterschied zwischen zwei Branches aufzuzeigen, indem Änderungen, die gemacht wurden, gegenübergestellt werden. Dadurch können Entwickler sehen, welche Dateien und Zeilen geändert wurden und welche Auswirkungen die Änderungen haben werden.

Ein „Pull Request“ ist eine Anfrage an den Repository-Administrator (in diesem Falle ausschließlich an uns selbst), um Änderungen in den Hauptzweig des Repositorys zu übernehmen. Der Administrator kann dann die Änderungen überprüfen, Kommentare dazu abgeben und sie gegebenenfalls genehmigen und zusammenführen oder auch ablehnen.

Nach Klick auf den Button „Compare & pull request“ gibt es folgendes Fenster in GitHub.

Wir sehen praktischerweise schon den Kommentar, den wir beim Commit der Änderungen angegeben haben. Es gibt aber auch die Möglichkeit, einen längeren, erkenntnisreichen Kommentar zu hinterlassen.

Wenn wir etwas nach unten scrollen, sehen wir die erfolgten Änderungen im Detail, wie wir es schon in Sourcetree kennenlernen durften.

Mit „Create pull request“ werden wir nun die Anfrage an den Administrator (auch wenn wir das selbst sind) stellen, unseren neuen Code in dem Branch „new_feature“ zu kontrollieren und bei Akzeptanz, in den Haupt-Branch „main“ zu übernehmen.

Schauen wir, was passiert, wer wir den Knopf drücken. Es öffnet sich ein neues Fenster im Browser.

Die Änderungen akzeptieren

Wir sehen oben die Überschrift des Commits, eine Beschreibung hatten wir nicht angegeben. Interessanterweise kann GitHub schon feststellen, dass es voraussichtlich keine Konflikte beim Zusammenführen der README.md-Datei auf dem Hauptbranch geben wird.

Bevor wir den Request jetzt final akzeptieren, scrollen wir noch kurz nach unten.

Hier könnten wir, wenn wir wollten, den Request ablehnen (und vorher noch einen Kommentar dazu hinterlassen.)

Aber wir haben uns ja dazu entschieden, den Request zu akzeptieren, also drücken wir beherzt auf „Merge pull request“.

Nach einer kleinen Zwischenfrage, auf die wir einen kleinen Kommentar (z.B. einen Dank an den fleißigen Programmierer) hinterlassen können, drücken wir jetzt aber wirklich final auf „Confirm merge“.

So sieht dann das Ergebnis aus:

Der Pull request wurde erfolgreich eingebunden und wurde jetzt geschlossen. Der Administrator hat nun noch die Gelegenheit den „new_feature“-Branch zu löschen oder nicht.

Es hängt von den individuellen Projektanforderungen und -richtlinien ab, ob er dies tut. Einige Teams bevorzugen das Löschen des Feature-Branches, um eine saubere und übersichtliche Branch-Historie zu erhalten, während andere Teams den Feature-Branch behalten möchten, um mögliche zukünftige Probleme leichter zu identifizieren und zu debuggen.

Es gibt jedoch auch Kompromisslösungen, wie zum Beispiel das Umbenennen des Feature-Branches in einen entsprechenden Namen, um anzuzeigen, dass er bereits gemerged wurde. In jedem Fall ist es wichtig, klare Richtlinien für das Branching-Verhalten im Team zu definieren und sicherzustellen, dass alle Teammitglieder diese Richtlinien verstehen und befolgen.

So sieht jetzt der Hauptbranch aus. Die Änderungen wurden komplett übernommen.

Die Änderungen im lokalen Repository – Pull oder Fetch

Damit jetzt alle am Projekt Beteiligten wieder auf den gleichen Stand der Entwicklung kommen – z.B. am Beginn eines neuen Arbeitstages, müssen sie die aktuellen Änderungen aus dem entfernten (remote) Repository auf GitHub übernehmen. Das schließt übrigens auch den Einreicher des „Pull requests“ selbst mit ein, denn er weiß ja noch nicht, dass seine Änderungen akzeptiert worden sind.

Um das zu erreichen, gibt es die Befehle „pull“ und „fetch“, die beide dafür da sind, Änderungen aus dem entfernten Repository zu übernehmen, sich aber in einem wichtigen Punkt unterscheiden.

Der Befehl „fetch” ruft alle Änderungen ab, die in einem Remote-Repository vorgenommen wurden, ohne diese in das lokale Repository zu integrieren. Dadurch können Sie sehen, welche Änderungen in dem Remote-Repository vorliegen, bevor Sie entscheiden, ob Sie sie zusammenführen möchten oder nicht.

Im Gegensatz zum Befehl „pull“ führt „fetch“ keine automatische Zusammenführung durch. Stattdessen müssen Sie entscheiden, ob Sie die Änderungen in Ihr lokales Repository integrieren möchten. Wir werden das jetzt mal machen.

Nach Klick auf „Fetch“ in der oberen Menüleiste erhalten wir drei Optionen zur Auswahl:

„Fetch from all remotes“ in Git bedeutet, dass alle Remote-Repositories, die mit dem lokalen Repository verbunden sind, nach Aktualisierungen durchsucht werden.

“Prune tracking branches no longer present on remote(s)?” entfernt die lokalen Tracking-Branches irreversible, die nicht mehr auf dem Remote-Repository vorhanden sind.

„Fetch all tags“ lädt alle Tags aus dem Repository herunter. Ein Tag ist ein Name, der einem bestimmten Commit zugewiesen wird, um ihn zu markieren. Es kann nützlich sein, alle Tags herunterzuladen, um sicherzustellen, dass Sie alle Informationen zu bestimmten Commits haben, einschließlich Informationen zu veröffentlichten Versionen oder Meilensteinen.

Ich belasse es fürs Erste bei den Default-Einstellungen.

Als Ergebnis erhalten wir … nichts, oder zumindest keine Änderungen. Woran liegt das? Das ist in unserem Falle leicht zu erklären, da wir ja die Einzigen sind, die Änderungen vorgeschlagen haben. Dementsprechend werden uns keine Differenzen aus anderen Pull/Merge requests angezeigt.

Wir können daher beruhigt „Pull“ in der Menüzeile drücken, um den Abgleich mit dem remote Repository abzuschließen

Nun haben wir vier Optionen zur Auswahl.

Mit „Commit merged changes immediately“ wird Git automatisch einen neuen Commit erstellen, der die zusammengeführten Änderungen beim Zusammenführen von Branches enthält. Wenn Sie das nicht möchten, bspw. aus Kontrollgründen, müssen Sie das später von Hand machen.

„Include messages from commits merged in merge commit“. Wenn diese Option ausgewählt ist, werden die Commit-Messages der zusammengeführten Commits in den Merge-Commit übernommen. Ich würde aus Gründen der Übersichtlichkeit darauf verzichten.

„Create a new commit even if fast-forward is possible?“ lassen wir fürs Erste deaktiviert, ansonsten könnten wir die neuen Commits aus dem Merge nicht mehr rückgängig machen.

„Rebase instead of merge“ – dieser Punkt dient dazu, die komplette Commit-Historie in einem linearen Verlauf zusammenzuführen. Das kann übersichtlicher sein, kann aber dazu führen, dass Informationen verloren gehen. Bei neuen Projekten sollte man sich einmalig festlegen, welcher der beiden Methoden genutzt wird. Es sollte tunlichst darauf geachtet werden, beide Methoden nicht zu vermischen. Ich lasse dieses Feld deaktiviert, da ich immer der Merge-Methode den Vorzug vor Rebase gebe.

Ich setze jetzt lediglich den Haken bei „Commit merged changes immediatly“, da ich davon ausgehe, dass beim Merge in GitHub alles richtig war.

Wie Sie sehen, hat sich nichts großartig getan, außer dass die kleine „2“ verschwunden ist, denn jetzt haben wir eigentlich unsere zuvor selbst erstellten Änderungen „gepullt“ haben. Das Ergebnis wäre ein anderes, wenn wir auch Änderungen anderer Personen übernommen hätten. Das werden wir im nächsten Kapitel sehen.

Zusammenfassung: Wir wissen nun, wie wir Änderungen über einen neuen Branch zu GitHub einspielen, wie wir diese Änderungen in den Hauptbranch einfügen und wie wir externe Änderungen im Code in unser Repository übernehmen können.