JCON EUROPE

From Git Panic to Git Zen: With a Little Help from AI | Pasha Finkelshteyn (EN)

45:09 · 20 Apr 2026 – 23 Apr 2026 · YouTube

About this talk

This talk discusses advanced Git techniques and the integration of AI to enhance Git workflows. The speaker, Pasha, shares personal anecdotes about facing challenges with Git, such as losing commits and dealing with messy commit history. He introduces AI tools that can aid in recovery processes, cleanup of commit histories, and features like Git bisect for identifying problematic commits. Key tools highlighted include Git reflog, bisect, and interactive rebase. By utilizing these tools along with AI, developers can streamline their workflows, avoid data loss, and efficiently manage complex version control tasks.

Full transcript

Okay. Hi everyone. You already saw the question, so you can just raise your hand if you think that you know Git. Nice. Uh let's check who knows git commit. Git push or even more people than git commit. I like it. Git pull. Okay, cool. Uh who knows how to commit only a part of code you changed with which is okay. Not that many. Okay. Okay. Okay. Okay.

Okay. So look like 10 years ago or maybe 14 years ago it happened to me. I lost four hours of work after accidental get reset who had a similar situation. You are also lucky. Come on. Like less than half of the audience that's cool. And who knows how to fight it? How to fix it? Some of you. So I guess others had to actually redo the work

they did for some time. Am I correct? I see. So and since everything is AI today, I can't exclude the situation that it wasn't you who performed greet probably your AI did it. I mean happened to me. I don't trust them anymore but still using them. So there are a lot of moments with G with G when you can feel some kind of panic like I lost

my commits after reset suddenly your customer finds a error on your site and you don't know who broke the build or you don't know who wrote this co code. There is costic here he told me yesterday brilliant phrase the most important part of investigation is not is to find that it's not you who was the reason of an issue my PR history is a mess it might

be familiar to many of you if you can if you maintain opensource whatever then you have a probably a terrible story because you have random contributors from the street we we are thankful for them They're doing a lot of useful work but they have small fix ID, small fix two, small small fix three and so on and then update update update update fix and this is how

our commit history will look like. And the thing is they all are fixable. Hey, they all are fixable and they all fixable with git and they are all fixable with AI. AI with Git could recover lot lots commits for you. It can find bug introducing commits and can clean up your messy history for you and many more things actually and this is the promise and this is

a slide about person giving you promises. I'm Pasha. I work for Bellsoft. I'm a developer advocate but I used to be a developer and I'm still developing a lot. I'm still writing a lot of code. You can look at my GitHub. It's terrifying honestly because with AI I can generate a ton of code and don't even just kidding. Uh I'm always reading my code. Uh I have

Twitter, I have site. Let's go. So in this talk we'll mostly talk about three things. Three three panics I just mentioned and three tools. It's reflo bisect and interactive rebase. who knows at least one of them almost the whole audience but I see at least six people who will learn three new tools which is also amazing so but before we jump into Git internals since it is

again an AI related talk give me a second it is an AI related uh we should talk about internals we should talk about MCP who knows what MCP okay I still have to explain because not everyone one. So the idea is you if you use things like cloud code or any other ch application which works with LLMs neither of them can just run your code be it

code working with git code working with your CRM or any other code they need a protocol to discover these tools and this and then call these tools and get structured results back. This protocols is called this protocol is called MCP model context protocol which is a fancy name for JSON RPC just JSON remote procedure call and the protocol here is very simple. You have this LLM be

it clude, be it uh codex whatever and it sends a special answer to your MCP client called tool call and there it says hey I want to this to call this tool with these arguments. Then MCB client over standard input output over or all over over SSE which is server sending events sends this request to your MCP server server and in my case it's spring boot and

it dispatches the call to methods annotated MCP tool. So my examples here today will be with Spring AI and Spring MCP but I have exactly the same written with Quarkus and the code is almost identical except like small nuances which are not important for the goals of this talk. Methods annotated as MCP tool will uh return records. If you use newer Java I hope you use newer

at least Java versions which already support records. they been converted to JSON usually by via Jackson. Then this Jackson is being sent back to MCV client which is our chat application and it's being wrapped into a tool result which is being resent to LM which can then process it. So our task here is essentially write code in the rightmost rectangle MCP tool and almost everything else will

be handled for the for us by Spring AI and MCP things. My project as I already said I'm writing it with uh spring AI. So I have to add one starter only one spring ai starter MCP server because I want to server to MCP server in my application and to work with git I will add one dependency which is called or Eclipse Jit. I was told that

it's been developed by folks from SAP which is just like 10 minutes ago which is surprising and very interesting. JG is a pure Java implementation of git. It doesn't call G from your machine. It is crossplatform because Java, right? So it it can do everything G like G common line can do for you which is very useful for us because such applications are much easier to to

run anywhere. We also will need a bit of config. It should not be web application because we work with local repositories right in our MCP. So we don't need web. It will be a standard IO. We have to disable banner. Who knows why do we need to disable banner in this application. Beautiful. Something useful for today. If you use standard input output protocol to communicate inside MCP,

you are not allowed to send anything but JSON RPC comments and requests and answers. That's all. If you turn on banner, it will crash your MCP client. Well, it will tell your MCP client that something is wrong and it won't even try to use your MCP tool. Then we are saying that it is stdio tool which is synchronous. Obviously we want to know results of our commands.

We will enable annotation scanner in our application because we want we don't want to write a boiler boiler play code. Hey use this class and we use this class. Now getting back to our panics. First panic is I lost my commits after reset. the one we were talking about. You did it on the wrong branch. Your AI did it for you. Your cat did it for you.

This is what I tell my manager. Hey, it's not me, it's my cat. And you want to fix it, but the whole history is lost. Except it isn't. When you perform get reset double dash hard, git remembers everything and it remembers everything for a long long time for 90 for 90 days, which is if you think about three months. And if you don't need your code for

3 months and you didn't notice that something was destroyed, then probably you don't really need it. But for this 90 days, commits are still in the object database. They're just not reachable from references in g. And this is how work and this is how you fix it with git ref log. First here we see we call git log one line and we see ah only only only

commit here. What do I do? You call git ref log and you see something like that. It very much reminds of git log. We also have hash sums. We also have uh head at curly braces and index of change in reverse order. So the zero is the newest change like and and then it goes to plus infinity. So if we want to roll back our reset which

is our last change we can call comment like this get reset double dash hard hash sum of our commit in ref lock or we can just say had curly brace one and this restored. Let me show you because on slides it's not that impressive. Whoa. Whoa. Duck. So I have I am a lazy person. So I will create um I will create a repository right now. Right

here it is here. Let's go to it. And if we call get log there we have only two commits by demo user. And guess who is the user and who broke our build to to fix it? We call Glog and see we see aha demo user did something wrong and they did reset moving to head till the one to return back. Come on we will call exactly

like on the slides get reset. Oh sorry I didn't show show you I have only two files. hard. Yes. And let's look at our repository. Now it's five five files back. And if you look at our history, our history is straight again. And we have all the commits. Nothing is lost. Obviously 53 seconds ago is not what you will see in real life. But you to I

mean this is something like what you see. So it is just two comments and essentially two seconds if you know your comments but question who is good under pressure here. Yeah me neither I have this issue so that I tend to forget my G comments to fix it. These days we can use AI obviously right we don't need to remember anything. So first piece of code we'll

be looking at I'll just switch to idea. Uh it is a service called g reflo service. Here you go which is marked as spring component. Nothing too interesting. Some methods like open g repository and so on. We have some important records here. Reflow record which contains everything you almost everything you saw in the log like index, short hash, full hash, author, timestamp, message and refloeration result. We

have this one very important method called MCP2 get ref log which can perform one one of three actions list, show and reset. list just lists the items in your reflo show shows one item from your reflo and reset actually recovers your work. Um and luckily for us jit has reflo built in built in so you can call just g.log then for example set reference which will which

by default will be had and this is the reference you actually usually need. Then we extract a bunch of records and we return reflock operation result. And for example to reset we are doing something like this. We are finding actual commit to which we want to return. Then we say when we are saying get reset set reference our target commit set mode hard because we we want

to return back to the stage we were before. And then there is call. And if you think about it, it is very much like what we call in our command line get uh reset double dash hard and then commit ID. Then it has some message and it returns refflock operation result. This is essentially everything you have to know. And yeah, let me show you how it is

supposed to work with I know it's a so you can be sure. Uh let's recreate this repository what was it? Come go task accidental reset. Yes, we have it. I have my crash client open right here. I did a dirty hack here. I disabled a bash tool. AIS are so good these days that they actually don't need this MCP. But you can see this G advanced MCP

right here, right? It will try. So, hey, I made boooo Um, what is the path of accidental result demo? Yep, something like that in Yeah, can you please fix it? Let's see. I'm not sure what happens. Yeah, should allow for the session. Let me check. It goes to log to reflog. I see someone you you saw that right? Someone did get reset double dash hard. Someone fixed.

Let's check. Well, actually fixed. By the way, I built this MCP with native image just for it to be single binary and it's just easier to use it this way. But obviously, you can just use Java-Jar and use MCP the very same way. Okay, back to our present presentation. By the way, if you don't have this MCP installed, AI very well can guide you through the very

same steps. It will explain you and after third explanation you will probably remember as I did because back then 10 years ago there were no AI around to help me. Second panic it is actually my favorite and it is very popular. So customer comes to me and says hey this feature doesn't work anymore and I'm asking hey did it ever work? and they they're like, "Yeah, it

used to work two weeks ago and now I have to somehow comb through the all the commits from two weeks ago to today to understand which which one actually broke their feature who had such a situation who knows how to solve it with Git without three four of you. Nice. Probably this will be helpful." Then the Git has an answer. It's called git and the process goes

like this. You are saying hey bisect start and there is a good commit and this is something two weeks ago or two week I don't know 15 days ago just to be sure and I know that there is a bad commit and it is my head like it is my master it is whatever or maybe it's not bad and good maybe it's old and new behavior so

you can instead of bad and good and you can say use old and new to understand when a behavior uh was introduced and g checks out midpoint between these two commits and and asks you hey is it good or bad and you're like get good and it switch and then with uh this finding midpoint you're very quickly finding the culprit and instead of lineer complexity it becomes

uh logarithmic complexity which is very nice let me show you an I will I have a lot of examples to explain bisect because I know sometimes it's not obvious. So imagine this is our commit history and the last commit is bad and bug is found there. Then we are looking at the first commit here and we know that it's good. It's certainly not A. We are checking

midpoint checking D and it is good. So we assume that everything from A to D is good. And you see that there are now empty circles. Now we'll check F. Obviously check is what? Check is bad or F is bad. So the culprit somewhere in E and F and then we are checking E and it's good and it means that the first bad commit is F. I

know that the developers of JVM use this feature all the time. uh except it's slightly more complicated than that because their bugs are tricky and sometimes there is a performance regression somewhere and you have to comb through thousands probably of commits and run your performance test to understand where was the uh where was it introduced. This is how it looks in common line. I can show in

mine hopefully. Go ask Um, Mr. is back. Okay. Oops. Interesting. So, I have this file class login, right? Do I? Yes. Java login dot Java login is broken. Uh, who knows why I can call it like this. and situ uh since which version I don't remember by the way did 24 probably K remembers I don't know 24 thank you K so it is broken so I have

to start my gct bisect start get bisect bad head Let me look at my history and I know let's check this commit out and check it. Java login Java login is working. So it is g bisect good. this now it just switches me between commits and the only thing I need to do is say hey it's working get bisect good get get bisect good and who could

think that The actual commit that broken everything is called refactor login authentication. Well, obviously if we look inside login Java right now, we'll see that static boolean login returns as false. By the way, you can use the same command because there is thing called there is thing called get bisect run and you can pass it a command it should use to check if your login is good.

Sorry, if you are in a good and or or in a bad shape and there is also so it could affirmate stuff for you and there is al also skip. Let's say that your code just doesn't compile at some point. It happens well to me it happens a a lot especially when I'm in active development stage. I have to go to sleep but I'm uh afraid of

fires in uh in a forest nearby. So I commit not compiling code which is fine. I will just skip it and then in a worst case scenario bisect will tell someone hey it seems like the c the bad commit is somewhere between these two or this three whatever the group of non-compilable uh non non non-compilable commits was okay and as I said it is much better than

combing through like 20 commits in a row let alone thousand commit in a row and if you Look at this git bice G by service please. I have this open repository everywhere because I want my services to be quite independent. Obviously I could separate them. And again descriptions are very important for LLMs. Uh they're not that important for us but it says that it can it supports

start good bad old new keep reset. You need reset when you realize that you did something wrong. Status let I don't know what status does. What What does it do? Oh, I okay whatever end view actions like I mean I I suppose that I suppose that it exists only here. I was like what why do I have it? Yes, this is why this is because I wanted

to understand from inside MCP do I do I bexing something right now or do I not and it's probably a bad idea to store some kind of I don't know state file but you you can do it as well and there is the a similar switch for what we do if it's start what is if it's good bad old new skip and so on and bisect doesn't

exist in jit so we have to implement and bisect ourselves. And the idea is we are working with a tree and we are using this function which we also have to write ourselves find next commit between last good hash and last bad hash and then and for that they have a thing called ref walk. This is essentially a object to walk over your tree and you want

to use ref walk. You never want to load all the commits you have into memory because if you imagine you're kernel Linux kernel it has I don't know hundreds of thousands of commits millions of commits and they all hold a lot of information. Ref walk essentially gives you like we store one data about one commit at a time. I'm oversimplifying but it is something like Yep. And

this is essentially like this is essentially it. I just have shown you how we bisect things. But let's try I actually don't know. Should we do you want to try it with AI or will you believe me that will you trust me? Trust me that it kind of works if we are Let's try. Okay. Get bisect reset. okay. Now we know that it's broken. Uh, let's see.

Hey, actually, let's create a new session just in case. Hey, in my repository created a bug with login. Could you please help me to find the broken commit? Something Let's see. It's It will be funny. It if it will just guess from log. Okay, it's smarter than me. It didn't It didn't even run anything. I should I I should work better on my commit messages. Sorry. But

yeah, my uh GitHub CP is too powerful. It can just comb through the commits and it's much faster than me. But obviously for more interesting bugs like this where it's not like we replace something useful with return false it should be more interesting but flow should be roughly the same except your AI should tell you hey well you probably want to run this comment right now to

check if it works or not and it will guide you through the process the same way. Now my pull request is a mess. Um there are 10 whip commits, there are debug locks commit, there are fixes for typos, all kinds of stuff you don't want to see in your pull request. And or your reviewer tells you please clean this before I merge. Happened to me multiple times

because I'm lazy. And for that we have a thing called interactive freebase. Who knows how to use interactive freebase? roughly 20 people in the audience which is a good sign probably someone else. So this is before and after. This before is how we want how we see our history. After how we want to see it and we obviously want to remove this all this WIP, all these

debugs and so on. We want to do something meaningful and for that we have interactive rebase plan. Interactive rebase plan is a frightening thing. It tells us, let me show you actually. Um, go task summar. Okay, works for me. I can want to do a lot of stuff with this commu. I see. Let's by the way, is it readable at all? I forgot to ask. Hopefully, it

is. So fix regax fit at the mail validation debug lock some of them we want to remove some some of them we we want to do something else here is how we do it in this case this repository is very small so I will do it like this I will say I don't I I want to start from the root from the place when there were no

commits at all and it opens me vim or for you it will open your editor of choice And for example debug lock I don't need it all right so I will just drop it there is an explanation right here that d is drop which stands for remove commit or for example this one I want to change wording in it so I will reward it and this validate

actually I want to merge this valid validation with this validation. So I will reward this and I will squash this. I know it is hard to read but the process itself is kind of straight straightforward. I am closing it and it says hey you wanted to edit your message and I will say it is I don't know fit validation done. Okay. And we hit some conflicts because

apparently I can't drop something. Uh it's either lo and lo and feed. Okay, this what what happens when we resolve conflicts manually? Uh we will drop this and we'll drop this from here. Uh and we'll say git base double dash continue. Uh I should add my file obviously. No get add typing is hard. Git base continue. Now I want to squash them together. So I will just

drop this part of the message. And this I want to reward. I will call it improved regax because you know it's very important to have nice commit names. And if you look at our logs history now, G history now, it is in my opinion actually better. First of all, it's shorter. Second of all, it's better better organized. We don't have a debug commit anymore. We squash together

validation commit. So now it's an atomic, it's one atomic commit which change changes only valid validation. Does it? Yes, it does. Yes. logs log and feature and so on. Um but this is messy. Who thinks they already understand how the things works? Okay, cool. Some of you happy for you. This is how it should be. Took me like two years to master it. But so interactive rebase

is also doable as an MCP server and get interactive rebase service. This is this is hard because interactive rebase is not a like a foundational thing in g. It's not like g has something like special common for interactive rebase. It is just arase with privileges. So I have to create to create the same flow as g does. Let's create this uh file. Give me a sec. Validate

plan. Validate plan. Where do we So lm should send us rebase action plan. If we look at what rebase action is, rebase action is something containing of type like squash, I don't know, uh fix up, drop, break. Break is very interesting. It's like at this point I want you to stop rebasing. I will figure it figure it out later. I used it couple of times because otherwise

in big histories when you do huge rebases it becomes too complicated to remember everything you did you did pick reward and so on. boom plan it can validate plan we need to validate plan because if the plan which LM created is not correct we won't be able to execute it but what is even more important we have since it's a potentially destructive operation we have to introduce

at least capability to dry run so if dry run which is just a flag we will generate to do file and we'll send it back to LLM to ask hey is it what you actually wanted to do and it will be able to kind of validate or it can send send us back to us back as a user and we can decide is it what I want

to do or not what I want to do by the way in this plan you can also reorder the commits and so on it is extremely power thing and if it's not a dry run then we execute rebase execute rebase is pretty simple we essentially parse the same file we just generated and then we execute actions one by one and when I'm saying simple it means 200

lines of code it is a comp complicated thing and I have all kinds of different exceptions what happens if we hit conflicts in ger decide what to do and we have to throw a runtime exception what what if user said edit edit is is amazing. It means I did something wrong in the pre one of previous commits. Now I want to change this commit for whatever reason

like commit a but five commits ago. Who knows commit commit amend. Nice. Who wanted to do five commit a but five commits ago? Some of you. Yes. Interactive rebase with edit is what you need. And you can do any kind of changes. You can change uh commit message. You can change files you commit. You can anything anything you can commit with with git will be And here

is just like small foundation rebase action with type commit message and lm sends exact schema. We'll have some method called interactive rebase. We'll annotate it with a bunch of annotations which should be useful for lm to do something. And this is very important. These descriptions are a part of the prompt sent to the model. So if they are too big, if they if you are too smart

describing your tools, then you will overflow the context and your LM will become dumb. It and it will do your rebase action worse than it could. If they are too short like on this slide, your LM won't even activate MCP tool unless you did what I did and disabled bash. So, so you should be careful. You should write them like a documentation for your future self and

for your LLM. This is what I already said. You should validate for in destructive operations. Please give your users a way to use dry run some in in some way. Obviously like you understand right this talk is about git but you can create MCP with the same ideas for anything you do for Jira I don't know for your CRM inside your company and so on. uh and

normalize nullable options. It is Yes, you have to return structure type which is easily understandable by LM because and chaining becomes more reliable if everything is structured. If you just return one huge line of text instead of JSON, lm will try to guess but guessing is worse than understanding the structure of JSON. Sorry, I don't have enough time to show the live demo and I'm really not

sure about it but with AI at least but you saw the idea l generate uh interactive free base with something array of JSON which are our actions and we'll execute squash reward I don't know pick squash and so on as I said I have to build this application as native image because I I think that actually native image is perfect for MCP tools especially especially local ones.

The way I do it is the following. I have this gcp application and I import runtime hints there gmcp application j run runtime skins and if you look at jg runtime hits it's the class I wrote which implements the interface runtime hits registister which does magic git by default is not native image compatible so I have to say a lot of things like please include them everything

in or eclipse jit manifest should be included also some of my records in my code you saw um I not are not by default accessed so I have to say bisect operation result by sect status commits dails and so on for for all of them please remember invoke decl constructors methods fields it's a simple code you can look it up on my GitHub it's simple also for

whatever reason if you use for the name task quarkus you don't need any of this magic it sees your records out of the box it sees it has extension for jit so it knows how to make jit work and so on so quarkus in this regard is pretty magical and we just ran through all of this so chat only I can only suggest comments but if you

have some mcp tool for your process. You can do better. Chat only AI can't perform validation and doesn't have any guardrails and you have to manually copy paste comments from AI which I honestly don't like. With tool calling, it's much safer. It can validate itself. You can put guard rails in place and so on. And it's just much more mature in my opinion. uh what I would

guide you away from and AI and I don't allow your AI do get push force because when you up your remote it's much harder to fix. It is possible if you have colleagues who have working copies of your repository or if you use ref log to recover to a previous but it's a mess you don't want to deal with. uh don't delete branches without backup and whole

lot of useful advice. Key takeaways. G already have tools for most of your problems. And if we have some time after this, I I'll show you more. Today we focused on reflo bisect and interactive rebase. AI can handle bookkeeping for you. You don't need to store the whole mental model of how git works in your head. even though it's good for you and really helped me to

write this talk that I remember this stuff and it can propose your base plan even without MCP you can ask your AI hey I did something wrong with my g or I want to change something can you look at my git log and propose me a rebase plan and it will do better or worse I don't know uh MCP tool and MCP tool params are your friends

when you use springai and the whole this thing the whole MCP tool is like 1200 lines of code. It's non-trivial, but it is understandable. And well, it works. Since we have three more minutes, I want to show you several more tools. G work tree. Who knows? G work tree. Oh, I would expect more hands because these days things like uh clo superpowers creates a work tree for

a work. Oh, no. Opensp spec creates uh work tree for a work automatically. Imagine the situation. You have your own working branch, but your colleague asks you to review their changes. Do you need to switch to their branch? Well, not necessarily. You can create a gork tree right inside your directory. There you can check out their branch. G doesn't look at griwork trees. They are not controlled.

Create a pull review, drop the work tree, and continue working on your thing. It it is almost no context switching. G cherry peek. Who knows gerrapic? Everyone knows gerrapic. Nice. G stash. Cool. Uh get blame investigations, right? Demo user and so on. Yeah. Yeah. Get blame. I wanted to show but you know we don't have enough time. Who knows get rare? One person. It is an amazing

thing. you actually need it and you don't know that you need it. You need to enable it in your g config today. Gary rare works the following way. It remembers how you resolved conflicts in your code and if it sees the same conflict again it will resolve it automatically exactly the same conflict. If something changes then not and it is especially use useful during interactive rebase. As

you saw, I did a conflict during my interactive rebase. Luckily, I didn't have to do it multiple I didn't have to do it multiple times in a row also because I have G enable enabled in my G config. Otherwise, I would probably have to do the same thing like three times in a row. G filter ripple no one. it it is I'm not sure if you need

it but imagine that you have a part of your closed source repository that you are ready to open source sometimes it happens and it's a monor repo in this case you will call g filter repo and extract something or you can remove things from your repository if you committed your secrets for example you can remove them from your repository altogether like this If if it finds a

file called secrets.enth, it will be removed from all the history. Before that, before git filter repo was introduced, you had to use a tool called BFG, which stands for big gun. Right now, you don't have to. G filter repo is official name by the way. It was written in Java. And with almost one minute to spare, thank you so much. Uh you can find all the code

and the slides somewhere on internets. If you can't come to me, I will give give them to you my site. And we have some time for one question probably questions. No. Thank you.

From event

JCON EUROPE

20 Apr 2026 – 23 Apr 2026

All event videos
Back to Watch