ai newsMo., 2. Nov.
EilmeldungAlphabet launches €6B bond sale in first test of AI debt since selloff

LLM-gestützter Helfer schreibt PR-Beschreibungen automatisch

Ein Entwickler hat einen Assistenten gebaut, der mithilfe eines LLM automatisch Beschreibungen für Pull Requests verfasst. Das spart Zeit und sorgt für verständliche Dokumentation der eigenen Änderungen.

dev.toMontag 16:01 · 02.11.DE4 Min. Lesezeit
Bild: dev.to

Du kennst dieses Gefühl. Du hast gerade deine ganze Seele in ein Feature gesteckt, deinen Branch gepusht, und dann... das gefürchtete leere Feld für die PR-Beschreibung. Dein Gehirn ist ausgebrannt. Du willst es einfach ausliefern, aber du solltest eine gute Beschreibung schreiben. Deine Änderungen erklären, das 'Warum', das 'Was'. Das ist eine mentale Abgabe, die ich schon immer gehasst habe.

Nach einer besonders anstrengenden Merge-Woche hatte ich beschlossen, dass genug ist. Was, wenn ein LLM diese Dinge wenigstens für mich entwerfen könnte? Ich wollte etwas, das nicht nur eine generische Zusammenfassung liefert, sondern den Kontext meiner Änderungen tatsächlich versteht. Also habe ich an einem aktuellen Wochenende angefangen, es zu bauen. So ist es gelaufen:

Mein erster Gedanke war: 'Hey, LLMs sind gut darin, Code zusammenzufassen, oder?' Was, wenn ich einfach den rohen git diff hineingebe? Einfach. Elegant. Vermutlich naiv. Aber genau da beginnen normalerweise meine besten (und schlechtesten) Ideen. Ich fand, der Ansatz mit minimalem Aufwand war der beste Weg, um zu starten und zu sehen, was schiefgeht.

Den Diff programmatisch zu bekommen ist ziemlich unkompliziert. Ein schneller subprocess.run-Aufruf in Python hat es getan. Ich vergleiche bei PRs normalerweise gegen main, also war es git diff main...HEAD. Die drei Punkte sind hier entscheidend, um alle Commits auf dem aktuellen Branch zu bekommen, nicht nur die Änderungen seit der Abzweigung von main.

def get_git_diff(): try: # Compare current branch HEAD against main result = subprocess.run( ['git', 'diff', 'main...HEAD'], capture_output=True, text=True, check=True ) return result.stdout except subprocess.CalledProcessError as e: print(f"Error getting diff: {e.stderr}") return None

Für dieses kleine Skript habe ich Python 3.10 verwendet, einfach weil das mein pyenv-Default war.

Als LLM habe ich gpt-3.5-turbo-0125 gewählt, wegen seiner Geschwindigkeit und Kosteneffizienz für erste Experimente. Mein erster Prompt war peinlich einfach: Summarize these git changes into a pull request description, explaining what was changed and why. Keep it concise. Danach habe ich einfach den Diff direkt angehängt.

Hier stieß ich auf die erste große Hürde. Ich hatte Magie erwartet, bekam aber... Vanilla. Das LLM spuckte Beschreibungen aus, die technisch korrekt waren, aber komplett ohne Kontext. Es sagte dann: 'Added a new function to handle user authentication', wusste aber nicht, warum diese Funktion nötig war oder welches Problem sie auf höherer Ebene löste.

Es war zu wörtlich am Code orientiert, wie ein Junior-Developer, der Zeilen liest und umformuliert. Wenn ich zum Beispiel einen Feature-Branch hatte, der einen Bug behob, bei dem sich Nutzer nach einem Passwort-Reset nicht einloggen konnten, sagte das LLM: 'Modified auth_service.py to update login_user function parameters.' Keine Erwähnung von 'Bugfix' oder 'Password-Reset-Flow'. Es war nur eine trockene Zusammenfassung der Code-Änderungen. Ich hatte etwa 2 Stunden in dieses erste Setup gesteckt und bekam etwas, das kaum besser war, als wenn ich selbst in den Diff geschaut hätte.

Ich habe schnell begriffen: Das LLM weiß nur, was man ihm gibt. Der git diff zeigt, was sich geändert hat, aber nicht warum. Das 'Warum' steckt oft in Commit-Messages oder vielleicht sogar in einer Jira-Ticket-ID, wenn man diszipliniert ist. Ich habe angefangen, die Commit-Messages des aktuellen Branches zu ergänzen.

python def get_git_log(): try: # Get commit messages for current branch (since diverging from main) result = subprocess.run( ['git', 'log', 'main...HEAD', '--pretty=format:%s%n%b'], capture_output=True, text=True, check=True ) return result.stdout except subprocess.CalledProcessError as e: print(f"Error getting log: {e.stderr}") return None

Dann habe ich meinen Prompt aktualisiert. Statt nur des Diffs habe ich einen Abschnitt für Commit Messages und Git Diff hinzugefügt und die Prompt-Anweisung angepasst: Analyze the following commit messages and git diff. Based on this information, generate a detailed and context-aware pull request description. Focus on the problem being solved, the solution implemented, and any relevant impact. Include a suggested title and a summary section. Das machte einen riesigen Unterschied. Plötzlich begann das LLM, die Punkte zwischen den Commits und den Code-Änderungen zu verbinden.

Jetzt hatte ich etwas wirklich Nützliches. Ich habe das Ganze in ein einfaches Python-Skript gepackt, das ein paar Argumente nimmt (wie --clipboard zum direkten Kopieren oder --print zum Anzeigen). Ich habe etwas Markdown-Formatierung in die Ausgabeanfrage des LLMs eingebaut, mit der Bitte um Abschnitte wie 'Title', 'Summary', 'Problem', 'Solution' und 'Changes'.

full_context = f"Commit Messages:\n{get_git_log()}\n\nGit Diff:\n{get_git_diff()}" prompt = f""" Analyze the following commit messages and git diff. Based on this information, generate a detailed and context-aware pull request description. Focus on the problem being solved, the solution implemented, and any relevant impact. Include a suggested title and the following sections:

Here's the context:\n\n{full_context} """

Diese kleine Automatisierung wird nicht deine gesamte Codebase schreiben, aber sie ist ein riesiger Gewinn für die Developer Experience. Sie bringt mich 80 Prozent des Weges, und ich fülle nur die letzten 20 Prozent mit konkreten Details oder Designentscheidungen aus. Es ist verrückt, wie groß der Unterschied durch das Hinzufügen der Commit-Messages war. Als Nächstes steht vielleicht die direkte Integration in meinen Editor an oder als Pre-Commit-Hook, der direkt vor dem Push einen PR-Beschreibungs-Entwurf generiert. Keine leeren Felder mehr für mich!

Automatisch übersetzt. Das Original auf Englisch ist unten aufklappbar.

Original (Englisch) anzeigen

You know that feeling. You've just poured your soul into a feature, pushed your branch, and then... the dreaded blank PR description box. Your brain is fried. You just want to ship it, but you should write a good description. Explaining your changes, the 'why,' the 'what.' It's a mental tax I've always hated.

After one particularly grueling merge week, I decided enough was enough. What if an LLM could at least draft these things for me? I wanted something that wasn't just a generic recap but actually understood the context of my changes. So, over a recent weekend, I set out to build it. Here’s how it went down:

My initial thought was, 'Hey, LLMs are good at summarizing code, right?' What if I just fed it the raw git diff? Simple. Elegant. Probably naive. But that's usually where my best (and worst) ideas start. I figured the minimal effort approach was the best way to get started and see what broke.

Getting the diff programmatically is pretty straightforward. A quick subprocess.run call in Python did the trick. I usually compare against main for PRs, so it was git diff main...HEAD. The... is crucial here to get all the commits on the current branch, not just the changes since the branch diverged from main.

def get_git_diff(): try: # Compare current branch HEAD against main result = subprocess.run( ['git', 'diff', 'main...HEAD'], capture_output=True, text=True, check=True ) return result.stdout except subprocess.CalledProcessError as e: print(f"Error getting diff: {e.stderr}") return None

I was using Python 3.10 for this little script, just because that's what my pyenv default was set to.

For the LLM, I picked gpt-3.5-turbo-0125 for its speed and cost-effectiveness for initial experiments. My first prompt was embarrassingly simple: Summarize these git changes into a pull request description, explaining what was changed and why. Keep it concise. Then I just appended the diff directly after that.

This is where I ran into my first major roadblock. I was expecting magic, but I got... vanilla. The LLM would spit out descriptions that were technically correct, but completely lacked context. It would say, 'Added a new function to handle user authentication,' but it wouldn't know why that function was needed, or what problem it solved from a higher level.

It was too literal to the code, like a junior dev reading lines and rephrasing them. For example, if I had a feature branch that fixed a bug where users couldn't log in after a password reset, the LLM would say: 'Modified auth_service.py to update login_user function parameters.' No mention of 'bug fix' or 'password reset flow.' It was just a dry recap of the code changes. I'd spent about 2 hours on this initial setup, only to get something barely better than me just looking at the diff.

I quickly realized the LLM only knows what you feed it. The git diff shows what changed, but not why. The 'why' often lives in commit messages, or maybe even in a Jira ticket ID if you're disciplined. I started experimenting with adding the commit messages from the current branch.

python def get_git_log(): try: # Get commit messages for current branch (since diverging from main) result = subprocess.run( ['git', 'log', 'main...HEAD', '--pretty=format:%s%n%b'], capture_output=True, text=True, check=True ) return result.stdout except subprocess.CalledProcessError as e: print(f"Error getting log: {e.stderr}") return None

Then I updated my prompt. Instead of just the diff, I added a section for Commit Messages and Git Diff and tweaked the prompt instruction: Analyze the following commit messages and git diff. Based on this information, generate a detailed and context-aware pull request description. Focus on the problem being solved, the solution implemented, and any relevant impact. Include a suggested title and a summary section. This made a huge difference. Suddenly, the LLM started connecting the dots between the commits and the code changes.

Now I had something genuinely useful. I wrapped it all up in a simple Python script that takes a few arguments (like --clipboard to copy directly, or --print to just show). I added some markdown formatting to the LLM's output request, asking for sections like 'Title', 'Summary', 'Problem', 'Solution', and 'Changes'.

full_context = f"Commit Messages:\n{get_git_log()}\n\nGit Diff:\n{get_git_diff()}" prompt = f""" Analyze the following commit messages and git diff. Based on this information, generate a detailed and context-aware pull request description. Focus on the problem being solved, the solution implemented, and any relevant impact. Include a suggested title and the following sections:

Here's the context:\n\n{full_context} """

This little automation isn't going to write your entire codebase, but it's a huge boost to developer experience. It gets me 80% of the way there, and I just fill in the last 20% with specific details or design decisions. It’s wild how much difference adding those commit messages made. Next up, maybe integrating it directly into my editor or as a pre-commit hook that generates a draft PR description right before I push. No more blank boxes for me!

Originaltitel: My LLM-Powered Sidekick for Painless PR DescriptionsQuelle: dev.to (dev.to). Original öffnen