git subtree

Wir alle kennen die Situation: Eine neue Idee, mit der wir unser bestehendes Projekt mit dem Namen alt erweitern, sodass wir sogleich im zugehörigen Repository ein Unterverzeichnis neueIdee anlegen. Die Idee stellt sich dann als so gut heraus, dass sie auch außerhalb des Projektes alt nützlich wäre. Es wäre also sehr sinnvoll ein neues Repository neu anzulegen, das nur den Inhalt des Unterverzeichnisses neueIdee enthalten soll. Tatsächlich scheint dieses Problem wohl so oft vorzukommen, dass es seit 2012 ein extra git Subcommand für diesen Zweck (und etwas kompliziertere Fälle) gibt: git subtree

Neues Repository aus einem Unterverzeichnis

alt/
├─ neueIdee/
│  ├─ lib.rs
├─ main.rs

Wir wechseln also in das Repository alt führen dort folgendes Kommando aus:

git subtree split --prefix=neueIdee/ --branch=nurNeueIdeeBranch

Dies erzeugt in diesem Repository zunächst einen neuen Branch nurNeueIdeeBranch, der nur den Inhalt von neueIdee hat — also ein anderes Wurzelverzeichnis. Dieser Branch enthält also eine neu geschriebene History, die nur aus Commits besteht, die (auch) Einfluss auf Dateien unterhalb von neueIdee hatten.

Nun können wir unser neues Repository neu anlegen und den soeben erzeugten Branch pullen.

cd .. ; mkdir neu ; cd neu
git init
git pull ../alt nurNeueIdeeBranch

Und schon haben wir ein neues Repository, das nur den gewünschten Inhalt hat.

alt/
├─ main.rs
neu/
├─ lib.rs

Möglicherweise wollen wir noch einen Commit im alten Repository tätigen, der das neueIdee Unterverzeichnis löscht. Möglicherweise müssen wir im neuen Repository noch Änderungen am Infrastrukturcode vornehmen.

Verschieben eines Unterverzeichnisses in ein bestehendes Repository

Womöglich fällt uns aber auch auf, dass der Code besser in ein anderes Repository statt eines Neuen passt? Vielleicht weil wir gerade dabei sind unseren Code in einem Monorepo zu sammeln? Auch kein Problem!

alt/
├─ neueIdee/
│  ├─ lib.rs
├─ main.rs
monorepo/
├─ project1/
├─ project2/

Wir haben oben bereits den nurNeueIdeeBranch erstellt, den wir nun in das Unterverzeichnis guteIdeedes Repositorys monorepo einfügen wollen. Auch hier hilft uns wieder git subtree weiter:

cd monorepo
git branch mitGuterIdeeBranch
git checkout mitGuterIdeeBranch
git subtree add --prefix=guteIdee/ ../alt nurNeueIdeeBranch

Sobald wir uns in dem neuen Branch mitGuterIdeeBranch überzeugt haben, dass alles zu unserer Zufriedenheit geklappt hat und wir möglicherweise noch Infrastrukturcode angepasst haben, können wir den Branch nach main mergen und sind fertig.

alt/
├─ neueIdee/
│  ├─ lib.rs
├─ main.rs
monorepo/
├─ project1/
├─ project2/
├─ guteIdee/
│  ├─ lib.rs

Raspberry Router

Für die Fälle, in denen man nur per WLAN einen Zugang zum Internet und nur einen Raspberry PI dabei hat, aber dennoch kabelgebundenes Internet braucht, notiere ich diesen Eintrag. Für weitergehende Informationen ist das Arch Linux Wiki, wie immer, empfehlenswert.

Wir müssen unseren Raspberry nur mit dem WLAN verbinden, das Ethernetkabel einstecken und spezifizieren, dass der Traffic vom einen zum anderen weitergeleitet werden sollen.

sysctl net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
iptables -A FORWARD -i wlan0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i eth0 -o wlan0 -j ACCEPT

Da unser Raspberry jetzt ein Router ist, muss er natürlich auch die üblichen Aufgaben eines Routers übernehmen und die Geräte, die per Ethernet verbunden werden per DHCP mit IP Adressen versorgen, beispielsweise mittels dnsmasq mit folgender Konfiguration in /etc/dnsmasq.conf:

#disable dns
port=0

dhcp-range=192.168.13.50,192.168.13.150,12h
bind-interfaces
dhcp-option=3,0.0.0.0
dhcp-option=6,1.1.1.1,8.8.8.8

Bei der Gelegenheit kann man auch dafür sorgen, dass sämtlicher Traffic durch ein VPN geleitet wird, indem man das wlan0 Interface oben durch das konfigurierte VPN-Interface austauscht (zB. durch tun0 für OpenVPN oder wg0 für WireGuard).

compress-pdf

Um ein pdf mit vielen zu hoch aufgelösten Bildern auf eine angemessene Dateigröße zu bringen (durch das Herunterskalieren und gegebenenfalls Neukodieren der Bilder), kann einfach ghostscript genutzt werden:

gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.4 -dPDFSETTINGS=/ebook -dEmbedAllFonts=true -dSubsetFonts=true -dNOPAUSE -dQUIET -dBATCH -sOutputFile=output.pdf input.pdf

Die Qualitätspresets sind screen, ebook, printer, prepress und default. Weitere Optionsnamen können durch folgendes Kommando ermittelt werden:

gs -sDEVICE=pdfwrite -o /dev/null -c "currentpagedevice { exch ==only ( ) print == } forall"