[{"data":1,"prerenderedAt":815},["ShallowReactive",2],{"/en-us/blog/kubernetes-101":3,"navigation-en-us":37,"banner-en-us":447,"footer-en-us":457,"blog-post-authors-en-us-Sara Kassabian":698,"blog-related-posts-en-us-kubernetes-101":712,"blog-promotions-en-us":751,"next-steps-en-us":805},{"id":4,"title":5,"authorSlugs":6,"body":8,"categorySlug":9,"config":10,"content":14,"description":8,"extension":25,"isFeatured":12,"meta":26,"navigation":27,"path":28,"publishedDate":20,"seo":29,"stem":33,"tagSlugs":34,"__hash__":36},"blogPosts/en-us/blog/kubernetes-101.yml","Kubernetes 101",[7],"sara-kassabian",null,"open-source",{"slug":11,"featured":12,"template":13},"kubernetes-101",false,"BlogPost",{"title":15,"description":16,"authors":17,"heroImage":19,"date":20,"body":21,"category":9,"tags":22},"Getting Started with Kubernetes","Pods, nodes, clusters – oh my! Get the lowdown on Kubernetes from Brendan O'Leary's talk at Contribute 2019.",[18],"Sara Kassabian","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749678474/Blog/Hero%20Images/clouds_kubernetes101.jpg","2019-10-24","\nKube-uh-not-a-clue?\n\nIt's the most common response to anyone who hears the term “Kubernetes” for the first time. If Kubernetes is, quite literally, Greek to you, then this blog post and [the corresponding video](https://www.youtube.com/watch?v=rq4GZ_GybN8) are two good places to start.\n\nWhile at [Contribute 2019](/blog/how-we-scaled-our-summits/), senior solutions manager [Brendan O’Leary](/company/team/#brendan) gave a presentation explaining the nuts and bolts of Kubernetes and how we use this open source tool at GitLab.\n\n## What is Kubernetes?\n\n“[Kubernetes](https://kubernetes.io/) is an open source system for automating deployment, scaling, and management of containerized applications,” according to the [Cloud Native Computing Foundation (CNCF)](https://www.cncf.io/).\n\n>“You'll hear [Kubernetes] called a lot of different things. You'll hear people say, ‘Well, it's a container scheduler.’ You'll hear people say it's a desired state manager. You'll hear people say it's an orchestrator,” says Brendan. “All these things just basically boil down to it's _a system that keeps the system how we want it to be_, which sounds kind of crazy. But when we're a software company for software companies, you can relate a little bit.”\n\nSo a system that keeps the system how we want it to be, what does that mean exactly?\n\nTo understand what Kubernetes is and what it does, it’s best to dig a bit deeper into the origin story of this technology.\n\nThe journey to Kubernetes started at Google, when infrastructure developers were searching for a way to deploy new applications on hundreds of thousands of globally distributed servers. The result was Borg, a private tool developed by Google engineers for this purpose. The engineers iterated on Borg to launch Project Seven – an open source project that wasn’t entirely Borg, but took elements of Borg to produce version 1.0 of Kubernetes.\n\nKubernetes, which translates from Greek to “pilot,\" “helmsman,” or \"governor,\" is managed by CNCF, a foundation created by Google and Linux to house Kubernetes and other open source computing projects.\n\n## The benefits of Kubernetes\n\nKubernetes is highly portable across multiple cloud platforms and simplifies container management across however many of them are in use. Kubernetes make it easy to achieve greater scalability, flexibility, and productivity.\n\nAnother big benefit of Kubernetes is of course the fact that it’s open source – it’s continuously improved and updated so that there are minimal workflow interruptions.\n\n## What features does Kubernetes offer?\n\nKubernetes is one of the fastest growing open-source software projects around today. Here are some of the reasons why:\n\n* Deployments can be sent to one cloud or multiple cloud services without losing any application functionality or performance.\n\n* Kubernetes automation capabilities handle scheduling and deploying containers regardless of where it comes from (on-premise, cloud, or other). The automation also auto-scales up and down to increase efficiency and reduce waste and it creates new containers if dealing with a heavy workload.\n\n* Kubernetes allows for rolling back an application change if something goes wrong.\n\n* The open-source nature of Kubernetes lets users take advantage of a vast ecosystem of open-source tools.\n\n* The software is never outdated due to previously launched versions – it is always updating.\n\n## The role of containers\n\nContainers are a lightweight technology that lets you securely run an application and its dependencies without impacting other containers or your operating system (OS). This makes containers more nimble and scalable than using other tools for application management, like virtual machines (VMs) or bare metal. Like VMs, containers can repeat the application as it’s in development, but unlike VMs, the container does not duplicate the OS each time and instead shares the infrastructure, container technology (e.g., Docker), and OS with the host computer. Containers are lightweight and easier to run on the cloud because the OS is not duplicated along with the application, but container technology can be challenging to manage without a tool.\n\n“As you get more and more containers... it has a huge advantage technically, but it really creates a mess as to how are we managing all these containers,” says Brendan. “And there’s another problem – bare metal, virtual machines, containers, these all assume to some extent that you know what's going on with the computer that's running them.”\n\n![Evolution of containers](https://about.gitlab.com/images/blogimages/evolution_of_containers.png){: .shadow.medium.center}\nContainers make application deployment simpler, but containers are hard to orchestrate without a tool like Kubernetes.\n\n\nBut orchestrating the various application deployments in containers is a level of abstraction that is difficult for the human mind to grapple with and is challenging to manage manually, which is where Kubernetes comes in.\n\n## Kubernetes as scheduler\n\nKubernetes is an open source container orchestrator that automates container management from deployment to scaling and operating.\n\nThere are a few key advantages to using Kubernetes, namely that the technology takes an extremely abstract method of application management – containers – and schedules the deployments to occur automatically.\n\nBrendan mentions other advantages to using Kubernetes, including that is can run routine health checks and is a very self-healing technology. A second key advantage to using Kubernetes for [DevOps](/topics/devops/) is that it is a declarative technology at its core. By using the [desired state manager](https://medium.com/@yannalbou/kubernetes-desired-state-4c5c4e873743), you can describe how you want your application to run and Kubernetes makes it happen.\n\n## Core Kubernetes concepts and definitions\n\n*   **Pod**: An abstraction that represents a group of one or more application containers. “The pod is just a unit that says these are the containers that represent the front end website, or these are the containers that represent the payment system,” explains Brendan.\n*   **Node**: A worker machine in Kubernetes that may be a VM or a physical machine (e.g., a computer), depending upon the cluster. The node often includes Docker, the pods (“group of containers”), and the VM or computer that includes the OS.\n*   **Cluster**: The highest level of abstraction in Kubernetes, it contains all the nodes, pods, and a **master** – which maintains the desired state of your application by orchestrating the nodes.\n*   **Service**: Defines a logical set of pods (e.g., “payment system”) and sets a policy about who can access them. “Pods come and go, but a service is forever,” or so the saying goes, Brendan says. “A pod is going to get scheduled into a node. But if that node went away, the fact that this pod is a member of this service means I've got to go find somewhere else to make a new pod that has this container running in it.” A service allows Kubernetes to route traffic to your application regardless of where the pod is running.\n\nThere are plenty of other buzzwords and phrases that are associated with Kubernetes, and Brendan dives into some of them in his presentation (captured in the video below). More concepts are explained on the [Kubernetes website at CNCF](https://kubernetes.io/docs/concepts/).\n\n## GitLab and Kubernetes\n\nThere are three key touchpoints between GitLab and Kubernetes:\n\n1. **GitLab is an application, so it can be run on Kubernetes.**\nIf a GitLab customer is already using a cloud native environment (i.e., containers and Kubernetes), then GitLab the application can be installed in that cloud native environment. We have already set-up [Helm Charts](https://docs.gitlab.com/charts/), which describe [how to install GitLab in a cloud native environment](https://docs.gitlab.com/charts/#installing-gitlab-using-the-helm-chart).\n2. **Customers that build their applications in GitLab using CI/CD can deploy to Kubernetes.**\nThe Configure team at GitLab works on the integration between GitLab and Kubernetes so developers can deploy their applications automatically to a Kubernetes cluster. [The GitLab and Kubernetes integration](https://docs.gitlab.com/ee/user/project/clusters/) allows customers to create and dismantle Kubernetes clusters, use review apps, run pipelines, deploy apps, view pod logs, detect and monitor Kubernetes, and much more. The Ops product teams at GitLab are always working to enhance the integration between Kubernetes and GitLab to make Auto DevOps faster and more efficient.\n3. **Moving our production system for GitLab.com to a Kubernetes cluster.**\nWe recently moved our giant GitLab.com application from Microsoft Azure [to a Google Cloud Platform](/blog/moving-to-gcp/). A key reason we changed platforms is that we wanted to move our GitLab.com project to a Kubernetes cluster. This project is ongoing but we are making major strides toward continuous deployment using Kubernetes.\n\n## Is Kubernetes easy to use?\n\nEveryone’s favorite answer: it depends. As with any software, there’s a learning curve to using Kubernetes (like having a basic understanding of how containers work). And it also may not be the right software fit for your needs. But if it is, adopting it doesn’t have to be complicated.\n\nKubernetes gives users the basic building blocks for creating developer projects while still allowing user flexibility where it’s needed. It can get a little more labor-intensive if users choose to build their own Kubernetes clusters rather than letting the service do it for them. But most companies don’t choose this route.\n\n## But wait, there’s more\n\nIf you have more questions, like why the heck Kubernetes is abbreviated to K8s, or are searching for more resources, you’re in luck. Brendan dives into more detail about some of the etymology, key concepts, vocabulary and even pop culture that shapes Kubernetes in his presentation. Watch the video below to learn more about how Kubernetes has been the impetus behind a major shift toward cloud native in the DevOps industry, and why we’re on the front lines of that change here at GitLab.\n\n### Watch\n\n\u003Cfigure class=\"video_container\">\n  \u003Ciframe src=\"https://www.youtube.com/embed/rq4GZ_GybN8\" frameborder=\"0\" allowfullscreen=\"true\"> \u003C/iframe>\n\u003C/figure>\n\n### Supplemental reading\n\n[Kubernetes and the open source community](/blog/kubernetes-chat-with-joe-beda/): A conversation between GitLab CEO [Sid Sijbrandij](/company/team/#sytses) and the co-creator of Kubernetes, Joe Beda.\n\n[Kubernetes and the future of cloud native](/blog/kubernetes-chat-with-kelsey-hightower/): Sid chats with Kelsey Hightower, Google staff developer advocate about cloud native.\n\n[Kubernetes, containers, cloud native – the basics](/blog/containers-kubernetes-basics/): Get a quick overview of the key Kubernetes concepts.\n\n[Kubernetes + GitLab](/solutions/kubernetes/): Explore how GitLab and Kubernetes interact at various touchpoints.\n\n[Cover Photo](https://unsplash.com/photos/9BJRGlqoIUk) by [Pero Kalimero](https://unsplash.com/@pericakalimerica?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/cloud?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)\n",[23,24],"cloud native","kubernetes","yml",{},true,"/en-us/blog/kubernetes-101",{"title":15,"description":16,"ogTitle":15,"ogDescription":16,"noIndex":12,"ogImage":19,"ogUrl":30,"ogSiteName":31,"ogType":32,"canonicalUrls":30},"https://about.gitlab.com/blog/kubernetes-101","https://about.gitlab.com","article","en-us/blog/kubernetes-101",[35,24],"cloud-native","jApr61FEHz3nVwbdEIQeU41mdG7lghRdWvOcZVy0Dbs",{"data":38},{"logo":39,"freeTrial":44,"sales":49,"login":54,"items":59,"search":367,"minimal":398,"duo":417,"switchNav":426,"pricingDeployment":437},{"config":40},{"href":41,"dataGaName":42,"dataGaLocation":43},"/","gitlab logo","header",{"text":45,"config":46},"Get free trial",{"href":47,"dataGaName":48,"dataGaLocation":43},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":50,"config":51},"Talk to sales",{"href":52,"dataGaName":53,"dataGaLocation":43},"/sales/","sales",{"text":55,"config":56},"Sign in",{"href":57,"dataGaName":58,"dataGaLocation":43},"https://gitlab.com/users/sign_in/","sign in",[60,87,182,187,288,348],{"text":61,"config":62,"cards":64},"Platform",{"dataNavLevelOne":63},"platform",[65,71,79],{"title":61,"description":66,"link":67},"The intelligent orchestration platform for DevSecOps",{"text":68,"config":69},"Explore our Platform",{"href":70,"dataGaName":63,"dataGaLocation":43},"/platform/",{"title":72,"description":73,"link":74},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":75,"config":76},"Meet GitLab Duo",{"href":77,"dataGaName":78,"dataGaLocation":43},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":80,"description":81,"link":82},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":83,"config":84},"Learn more",{"href":85,"dataGaName":86,"dataGaLocation":43},"/why-gitlab/","why gitlab",{"text":88,"left":27,"config":89,"link":91,"lists":95,"footer":164},"Product",{"dataNavLevelOne":90},"solutions",{"text":92,"config":93},"View all Solutions",{"href":94,"dataGaName":90,"dataGaLocation":43},"/solutions/",[96,120,143],{"title":97,"description":98,"link":99,"items":104},"Automation","CI/CD and automation to accelerate deployment",{"config":100},{"icon":101,"href":102,"dataGaName":103,"dataGaLocation":43},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[105,109,112,116],{"text":106,"config":107},"CI/CD",{"href":108,"dataGaLocation":43,"dataGaName":106},"/solutions/continuous-integration/",{"text":72,"config":110},{"href":77,"dataGaLocation":43,"dataGaName":111},"gitlab duo agent platform - product menu",{"text":113,"config":114},"Source Code Management",{"href":115,"dataGaLocation":43,"dataGaName":113},"/solutions/source-code-management/",{"text":117,"config":118},"Automated Software Delivery",{"href":102,"dataGaLocation":43,"dataGaName":119},"Automated software delivery",{"title":121,"description":122,"link":123,"items":128},"Security","Deliver code faster without compromising security",{"config":124},{"href":125,"dataGaName":126,"dataGaLocation":43,"icon":127},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[129,133,138],{"text":130,"config":131},"Application Security Testing",{"href":125,"dataGaName":132,"dataGaLocation":43},"Application security testing",{"text":134,"config":135},"Software Supply Chain Security",{"href":136,"dataGaLocation":43,"dataGaName":137},"/solutions/supply-chain/","Software supply chain security",{"text":139,"config":140},"Software Compliance",{"href":141,"dataGaName":142,"dataGaLocation":43},"/solutions/software-compliance/","software compliance",{"title":144,"link":145,"items":150},"Measurement",{"config":146},{"icon":147,"href":148,"dataGaName":149,"dataGaLocation":43},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[151,155,159],{"text":152,"config":153},"Visibility & Measurement",{"href":148,"dataGaLocation":43,"dataGaName":154},"Visibility and Measurement",{"text":156,"config":157},"Value Stream Management",{"href":158,"dataGaLocation":43,"dataGaName":156},"/solutions/value-stream-management/",{"text":160,"config":161},"Analytics & Insights",{"href":162,"dataGaLocation":43,"dataGaName":163},"/solutions/analytics-and-insights/","Analytics and insights",{"title":165,"items":166},"GitLab for",[167,172,177],{"text":168,"config":169},"Enterprise",{"href":170,"dataGaLocation":43,"dataGaName":171},"/enterprise/","enterprise",{"text":173,"config":174},"Small Business",{"href":175,"dataGaLocation":43,"dataGaName":176},"/small-business/","small business",{"text":178,"config":179},"Public Sector",{"href":180,"dataGaLocation":43,"dataGaName":181},"/solutions/public-sector/","public sector",{"text":183,"config":184},"Pricing",{"href":185,"dataGaName":186,"dataGaLocation":43,"dataNavLevelOne":186},"/pricing/","pricing",{"text":188,"config":189,"link":191,"lists":195,"feature":275},"Resources",{"dataNavLevelOne":190},"resources",{"text":192,"config":193},"View all resources",{"href":194,"dataGaName":190,"dataGaLocation":43},"/resources/",[196,229,247],{"title":197,"items":198},"Getting started",[199,204,209,214,219,224],{"text":200,"config":201},"Install",{"href":202,"dataGaName":203,"dataGaLocation":43},"/install/","install",{"text":205,"config":206},"Quick start guides",{"href":207,"dataGaName":208,"dataGaLocation":43},"/get-started/","quick setup checklists",{"text":210,"config":211},"Learn",{"href":212,"dataGaLocation":43,"dataGaName":213},"https://university.gitlab.com/","learn",{"text":215,"config":216},"Product documentation",{"href":217,"dataGaName":218,"dataGaLocation":43},"https://docs.gitlab.com/","product documentation",{"text":220,"config":221},"Best practice videos",{"href":222,"dataGaName":223,"dataGaLocation":43},"/getting-started-videos/","best practice videos",{"text":225,"config":226},"Integrations",{"href":227,"dataGaName":228,"dataGaLocation":43},"/integrations/","integrations",{"title":230,"items":231},"Discover",[232,237,242],{"text":233,"config":234},"Customer success stories",{"href":235,"dataGaName":236,"dataGaLocation":43},"/customers/","customer success stories",{"text":238,"config":239},"Blog",{"href":240,"dataGaName":241,"dataGaLocation":43},"/blog/","blog",{"text":243,"config":244},"Remote",{"href":245,"dataGaName":246,"dataGaLocation":43},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":248,"items":249},"Connect",[250,255,260,265,270],{"text":251,"config":252},"GitLab Services",{"href":253,"dataGaName":254,"dataGaLocation":43},"/services/","services",{"text":256,"config":257},"Community",{"href":258,"dataGaName":259,"dataGaLocation":43},"/community/","community",{"text":261,"config":262},"Forum",{"href":263,"dataGaName":264,"dataGaLocation":43},"https://forum.gitlab.com/","forum",{"text":266,"config":267},"Events",{"href":268,"dataGaName":269,"dataGaLocation":43},"/events/","events",{"text":271,"config":272},"Partners",{"href":273,"dataGaName":274,"dataGaLocation":43},"/partners/","partners",{"backgroundColor":276,"textColor":277,"text":278,"image":279,"link":283},"#2f2a6b","#fff","Insights for the future of software development",{"altText":280,"config":281},"the source promo card",{"src":282},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":284,"config":285},"Read the latest",{"href":286,"dataGaName":287,"dataGaLocation":43},"/the-source/","the source",{"text":289,"config":290,"lists":292},"Company",{"dataNavLevelOne":291},"company",[293],{"items":294},[295,300,306,308,313,318,323,328,333,338,343],{"text":296,"config":297},"About",{"href":298,"dataGaName":299,"dataGaLocation":43},"/company/","about",{"text":301,"config":302,"footerGa":305},"Jobs",{"href":303,"dataGaName":304,"dataGaLocation":43},"/jobs/","jobs",{"dataGaName":304},{"text":266,"config":307},{"href":268,"dataGaName":269,"dataGaLocation":43},{"text":309,"config":310},"Leadership",{"href":311,"dataGaName":312,"dataGaLocation":43},"/company/team/e-group/","leadership",{"text":314,"config":315},"Team",{"href":316,"dataGaName":317,"dataGaLocation":43},"/company/team/","team",{"text":319,"config":320},"Handbook",{"href":321,"dataGaName":322,"dataGaLocation":43},"https://handbook.gitlab.com/","handbook",{"text":324,"config":325},"Investor relations",{"href":326,"dataGaName":327,"dataGaLocation":43},"https://ir.gitlab.com/","investor relations",{"text":329,"config":330},"Trust Center",{"href":331,"dataGaName":332,"dataGaLocation":43},"/security/","trust center",{"text":334,"config":335},"AI Transparency Center",{"href":336,"dataGaName":337,"dataGaLocation":43},"/ai-transparency-center/","ai transparency center",{"text":339,"config":340},"Newsletter",{"href":341,"dataGaName":342,"dataGaLocation":43},"/company/contact/#contact-forms","newsletter",{"text":344,"config":345},"Press",{"href":346,"dataGaName":347,"dataGaLocation":43},"/press/","press",{"text":349,"config":350,"lists":351},"Contact us",{"dataNavLevelOne":291},[352],{"items":353},[354,357,362],{"text":50,"config":355},{"href":52,"dataGaName":356,"dataGaLocation":43},"talk to sales",{"text":358,"config":359},"Support portal",{"href":360,"dataGaName":361,"dataGaLocation":43},"https://support.gitlab.com","support portal",{"text":363,"config":364},"Customer portal",{"href":365,"dataGaName":366,"dataGaLocation":43},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":368,"login":369,"suggestions":376},"Close",{"text":370,"link":371},"To search repositories and projects, login to",{"text":372,"config":373},"gitlab.com",{"href":57,"dataGaName":374,"dataGaLocation":375},"search login","search",{"text":377,"default":378},"Suggestions",[379,381,385,387,391,395],{"text":72,"config":380},{"href":77,"dataGaName":72,"dataGaLocation":375},{"text":382,"config":383},"Code Suggestions (AI)",{"href":384,"dataGaName":382,"dataGaLocation":375},"/solutions/code-suggestions/",{"text":106,"config":386},{"href":108,"dataGaName":106,"dataGaLocation":375},{"text":388,"config":389},"GitLab on AWS",{"href":390,"dataGaName":388,"dataGaLocation":375},"/partners/technology-partners/aws/",{"text":392,"config":393},"GitLab on Google Cloud",{"href":394,"dataGaName":392,"dataGaLocation":375},"/partners/technology-partners/google-cloud-platform/",{"text":396,"config":397},"Why GitLab?",{"href":85,"dataGaName":396,"dataGaLocation":375},{"freeTrial":399,"mobileIcon":404,"desktopIcon":409,"secondaryButton":412},{"text":400,"config":401},"Start free trial",{"href":402,"dataGaName":48,"dataGaLocation":403},"https://gitlab.com/-/trials/new/","nav",{"altText":405,"config":406},"Gitlab Icon",{"src":407,"dataGaName":408,"dataGaLocation":403},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":405,"config":410},{"src":411,"dataGaName":408,"dataGaLocation":403},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":413,"config":414},"Get Started",{"href":415,"dataGaName":416,"dataGaLocation":403},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":418,"mobileIcon":422,"desktopIcon":424},{"text":419,"config":420},"Learn more about GitLab Duo",{"href":77,"dataGaName":421,"dataGaLocation":403},"gitlab duo",{"altText":405,"config":423},{"src":407,"dataGaName":408,"dataGaLocation":403},{"altText":405,"config":425},{"src":411,"dataGaName":408,"dataGaLocation":403},{"button":427,"mobileIcon":432,"desktopIcon":434},{"text":428,"config":429},"/switch",{"href":430,"dataGaName":431,"dataGaLocation":403},"#contact","switch",{"altText":405,"config":433},{"src":407,"dataGaName":408,"dataGaLocation":403},{"altText":405,"config":435},{"src":436,"dataGaName":408,"dataGaLocation":403},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":438,"mobileIcon":443,"desktopIcon":445},{"text":439,"config":440},"Back to pricing",{"href":185,"dataGaName":441,"dataGaLocation":403,"icon":442},"back to pricing","GoBack",{"altText":405,"config":444},{"src":407,"dataGaName":408,"dataGaLocation":403},{"altText":405,"config":446},{"src":411,"dataGaName":408,"dataGaLocation":403},{"title":448,"button":449,"config":454},"See how agentic AI transforms software delivery",{"text":450,"config":451},"Watch GitLab Transcend now",{"href":452,"dataGaName":453,"dataGaLocation":43},"/events/transcend/virtual/","transcend event",{"layout":455,"icon":456,"disabled":27},"release","AiStar",{"data":458},{"text":459,"source":460,"edit":466,"contribute":471,"config":476,"items":481,"minimal":687},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":461,"config":462},"View page source",{"href":463,"dataGaName":464,"dataGaLocation":465},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":467,"config":468},"Edit this page",{"href":469,"dataGaName":470,"dataGaLocation":465},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":472,"config":473},"Please contribute",{"href":474,"dataGaName":475,"dataGaLocation":465},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":477,"facebook":478,"youtube":479,"linkedin":480},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[482,529,582,626,653],{"title":183,"links":483,"subMenu":498},[484,488,493],{"text":485,"config":486},"View plans",{"href":185,"dataGaName":487,"dataGaLocation":465},"view plans",{"text":489,"config":490},"Why Premium?",{"href":491,"dataGaName":492,"dataGaLocation":465},"/pricing/premium/","why premium",{"text":494,"config":495},"Why Ultimate?",{"href":496,"dataGaName":497,"dataGaLocation":465},"/pricing/ultimate/","why ultimate",[499],{"title":500,"links":501},"Contact Us",[502,505,507,509,514,519,524],{"text":503,"config":504},"Contact sales",{"href":52,"dataGaName":53,"dataGaLocation":465},{"text":358,"config":506},{"href":360,"dataGaName":361,"dataGaLocation":465},{"text":363,"config":508},{"href":365,"dataGaName":366,"dataGaLocation":465},{"text":510,"config":511},"Status",{"href":512,"dataGaName":513,"dataGaLocation":465},"https://status.gitlab.com/","status",{"text":515,"config":516},"Terms of use",{"href":517,"dataGaName":518,"dataGaLocation":465},"/terms/","terms of use",{"text":520,"config":521},"Privacy statement",{"href":522,"dataGaName":523,"dataGaLocation":465},"/privacy/","privacy statement",{"text":525,"config":526},"Cookie preferences",{"dataGaName":527,"dataGaLocation":465,"id":528,"isOneTrustButton":27},"cookie preferences","ot-sdk-btn",{"title":88,"links":530,"subMenu":539},[531,535],{"text":532,"config":533},"DevSecOps platform",{"href":70,"dataGaName":534,"dataGaLocation":465},"devsecops platform",{"text":536,"config":537},"AI-Assisted Development",{"href":77,"dataGaName":538,"dataGaLocation":465},"ai-assisted development",[540],{"title":541,"links":542},"Topics",[543,548,553,558,563,568,572,577],{"text":544,"config":545},"CICD",{"href":546,"dataGaName":547,"dataGaLocation":465},"/topics/ci-cd/","cicd",{"text":549,"config":550},"GitOps",{"href":551,"dataGaName":552,"dataGaLocation":465},"/topics/gitops/","gitops",{"text":554,"config":555},"DevOps",{"href":556,"dataGaName":557,"dataGaLocation":465},"/topics/devops/","devops",{"text":559,"config":560},"Version Control",{"href":561,"dataGaName":562,"dataGaLocation":465},"/topics/version-control/","version control",{"text":564,"config":565},"DevSecOps",{"href":566,"dataGaName":567,"dataGaLocation":465},"/topics/devsecops/","devsecops",{"text":569,"config":570},"Cloud Native",{"href":571,"dataGaName":23,"dataGaLocation":465},"/topics/cloud-native/",{"text":573,"config":574},"AI for Coding",{"href":575,"dataGaName":576,"dataGaLocation":465},"/topics/devops/ai-for-coding/","ai for coding",{"text":578,"config":579},"Agentic AI",{"href":580,"dataGaName":581,"dataGaLocation":465},"/topics/agentic-ai/","agentic ai",{"title":583,"links":584},"Solutions",[585,587,589,594,598,601,605,608,610,613,616,621],{"text":130,"config":586},{"href":125,"dataGaName":130,"dataGaLocation":465},{"text":119,"config":588},{"href":102,"dataGaName":103,"dataGaLocation":465},{"text":590,"config":591},"Agile development",{"href":592,"dataGaName":593,"dataGaLocation":465},"/solutions/agile-delivery/","agile delivery",{"text":595,"config":596},"SCM",{"href":115,"dataGaName":597,"dataGaLocation":465},"source code management",{"text":544,"config":599},{"href":108,"dataGaName":600,"dataGaLocation":465},"continuous integration & delivery",{"text":602,"config":603},"Value stream management",{"href":158,"dataGaName":604,"dataGaLocation":465},"value stream management",{"text":549,"config":606},{"href":607,"dataGaName":552,"dataGaLocation":465},"/solutions/gitops/",{"text":168,"config":609},{"href":170,"dataGaName":171,"dataGaLocation":465},{"text":611,"config":612},"Small business",{"href":175,"dataGaName":176,"dataGaLocation":465},{"text":614,"config":615},"Public sector",{"href":180,"dataGaName":181,"dataGaLocation":465},{"text":617,"config":618},"Education",{"href":619,"dataGaName":620,"dataGaLocation":465},"/solutions/education/","education",{"text":622,"config":623},"Financial services",{"href":624,"dataGaName":625,"dataGaLocation":465},"/solutions/finance/","financial services",{"title":188,"links":627},[628,630,632,634,637,639,641,643,645,647,649,651],{"text":200,"config":629},{"href":202,"dataGaName":203,"dataGaLocation":465},{"text":205,"config":631},{"href":207,"dataGaName":208,"dataGaLocation":465},{"text":210,"config":633},{"href":212,"dataGaName":213,"dataGaLocation":465},{"text":215,"config":635},{"href":217,"dataGaName":636,"dataGaLocation":465},"docs",{"text":238,"config":638},{"href":240,"dataGaName":241,"dataGaLocation":465},{"text":233,"config":640},{"href":235,"dataGaName":236,"dataGaLocation":465},{"text":243,"config":642},{"href":245,"dataGaName":246,"dataGaLocation":465},{"text":251,"config":644},{"href":253,"dataGaName":254,"dataGaLocation":465},{"text":256,"config":646},{"href":258,"dataGaName":259,"dataGaLocation":465},{"text":261,"config":648},{"href":263,"dataGaName":264,"dataGaLocation":465},{"text":266,"config":650},{"href":268,"dataGaName":269,"dataGaLocation":465},{"text":271,"config":652},{"href":273,"dataGaName":274,"dataGaLocation":465},{"title":289,"links":654},[655,657,659,661,663,665,667,671,676,678,680,682],{"text":296,"config":656},{"href":298,"dataGaName":291,"dataGaLocation":465},{"text":301,"config":658},{"href":303,"dataGaName":304,"dataGaLocation":465},{"text":309,"config":660},{"href":311,"dataGaName":312,"dataGaLocation":465},{"text":314,"config":662},{"href":316,"dataGaName":317,"dataGaLocation":465},{"text":319,"config":664},{"href":321,"dataGaName":322,"dataGaLocation":465},{"text":324,"config":666},{"href":326,"dataGaName":327,"dataGaLocation":465},{"text":668,"config":669},"Sustainability",{"href":670,"dataGaName":668,"dataGaLocation":465},"/sustainability/",{"text":672,"config":673},"Diversity, inclusion and belonging (DIB)",{"href":674,"dataGaName":675,"dataGaLocation":465},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":329,"config":677},{"href":331,"dataGaName":332,"dataGaLocation":465},{"text":339,"config":679},{"href":341,"dataGaName":342,"dataGaLocation":465},{"text":344,"config":681},{"href":346,"dataGaName":347,"dataGaLocation":465},{"text":683,"config":684},"Modern Slavery Transparency Statement",{"href":685,"dataGaName":686,"dataGaLocation":465},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":688},[689,692,695],{"text":690,"config":691},"Terms",{"href":517,"dataGaName":518,"dataGaLocation":465},{"text":693,"config":694},"Cookies",{"dataGaName":527,"dataGaLocation":465,"id":528,"isOneTrustButton":27},{"text":696,"config":697},"Privacy",{"href":522,"dataGaName":523,"dataGaLocation":465},[699],{"id":700,"title":18,"body":8,"config":701,"content":703,"description":8,"extension":25,"meta":707,"navigation":27,"path":708,"seo":709,"stem":710,"__hash__":711},"blogAuthors/en-us/blog/authors/sara-kassabian.yml",{"template":702},"BlogAuthor",{"name":18,"config":704},{"headshot":705,"ctfId":706},"","skassabian",{},"/en-us/blog/authors/sara-kassabian",{},"en-us/blog/authors/sara-kassabian","6cCCPpjzkCDfb77tMVCyG8_FImRVQXA2VCMyiAjhFX0",[713,727,739],{"content":714,"config":725},{"title":715,"description":716,"authors":717,"heroImage":719,"date":720,"category":9,"tags":721,"body":724},"What’s new in Git 2.54.0?","Learn about release contributions, including new repository maintenance, a new command to edit commit history, a replacement for git-sizer(1), and more.",[718],"Patrick Steinhardt","https://res.cloudinary.com/about-gitlab-com/image/upload/v1776711651/sj7xxyyuimlarswbyft5.png","2026-04-20",[722,723,259],"open source","git","The Git project recently released [Git 2.54.0](https://lore.kernel.org/git/xmqqa4uxsjrs.fsf@gitster.g/T/#u). Let's look at a few notable highlights from this release, which includes contributions from the Git team at GitLab.\n\n## Pluggable Object Databases\n\nGit already has the ability to store references with either the \"files\" backend or with the [\"reftable\" backend](https://about.gitlab.com/blog/a-beginners-guide-to-the-git-reftable-format/). This is achieved by having proper abstractions in Git that allows us to have different backends.\n\nBut references are just one of the two important types of data that are stored in repositories, with the other being objects. Objects are stored in the object database, and each object database in turn consists of multiple object sources where objects can be read from or written to. Each object source either stores individual objects as so-called \"loose\" objects, or compresses multiple objects into a \"packfile\" in your `.git/objects` directory.\n\nUntil now, however, these sources did not have a proper abstraction boundary, so the storage format for objects is completely hardcoded into Git. But this is finally changing with pluggable object databases! The concept is straightforward and similar to how we did this for references in the past: Instead of having hardcoded code paths for how to store objects, we introduce an abstraction boundary that allows us to have different backends for storing objects.\n\nWhile the idea is simple, the implementation is not, as we have hardcoded assumptions about the storage formats used in Git all over the place. In fact, we have started working on this topic in Git 2.48, which was released in January 2025. Initially, we focused on making object-related subsystems self-contained and creating proper subsystems for the existing backends that we had in Git.\n\nWith Git 2.54, we have now reached a milestone: The object database backend is now pluggable. Not all of Git's functionality is covered yet, but introducing an alternate backend that handles a meaningful subset of operations is now a realistic undertaking.\n\nFor now, only local workflows like creating commits, showing commit graphs, or performing merges will work with such an alternative implementation. This notably excludes anything that interacts with a remote, such as when you want to fetch or push changes. Regardless, this is the culmination of almost two years of work spanning across almost 400 commits that have been merged upstream, and we will of course continue to iterate on this effort.\n\nSo why does this matter? The idea is that it becomes practical to introduce new storage formats into Git. Examples could be:\n- A storage format that is able to store large binary files more efficiently\n  than packfiles do today\n\n- A storage format that is custom-tailored for GitLab to ensure that we can\n  serve repositories to our users even more efficiently than we currently can\n\n\nThis is a large-scale effort that is likely to shape the future of Git and GitLab.\n\n*This project was led by [Patrick Steinhardt](https://gitlab.com/pks-gitlab).*\n\n## Easier editing of your commit history\n\nIn many software development projects it is common practice for developers to not only polish the code they want to contribute, but to also polish the commit history so that it becomes easy to review. The result is a set of small and atomic commits that each do one thing, with a good commit message that describes the intent of the commit as well as specific nuances.\n\nOf course, more often than not, these atomic commits are not something that just happens naturally during the development process. Instead, the author of the changes will gain a better understanding of what they are while iterating on them, and the way to split up the commits will become clearer over time. Furthermore, the subsequent review process may result in feedback that requires changes to the crafted commits.\n\nThe consequence of this process is that the developer will have to rewrite their commit history many times during the development process. Historically, Git has allowed for this use case via [interactive rebases](https://git-scm.com/docs/git-rebase#_interactive_mode). These interactive rebases are an extremely powerful tool: They let you reorder commits, rewrite commit messages, squash multiple commits together, or perform arbitrary edits of any commit.\n\nBut they are also somewhat arcane and hard to understand. The user needs to figure out the base commit for the rebase, they need to understand how to edit a somewhat obscure \"instruction sheet,\" and they need to be aware of how the stateful rebasing process works. For example, users are presented with an instruction sheet similar to the following when rebasing a topic branch:\n\n```shell\npick b60623f382 # t: detect errors outside of test cases # empty\npick b80cb55882 # t: prepare `test_match_signal ()` calls for `set -e`\npick 5ffe397f30 # t: prepare `test_must_fail ()` for `set -e`\npick 5e9b0cf5e1 # t: prepare `stop_git_daemon ()` for `set -e`\npick 299561e7a2 # t: prepare `git config --unset` calls for `set -e`\npick ed0e7ca2b5 # t: detect errors outside of test cases\n```\n\nSo while interactive rebases are powerful, they are also quite intimidating for the average user.\n\nIt doesn't have to be this way, though. Tools like [Jujutsu](https://www.jj-vcs.dev/latest/) provide interfaces that are much easier to use compared to Git, as you can for example simply execute `jj split` to split up a commit into two commits. With Git and interactive rebases, this use case requires a lot of different steps with confusing command line arguments.\n\nWe have thus taken inspiration from Jujutsu and have introduced a new git-history(1) command into Git that is the foundation for better history editing. For now, this command has two subcommands:\n\n- `git history reword` allows you to easily rewrite a commit message. You simply\n  give it the commit whose message you want to reword, Git asks you for the new\n  commit message, and that's it.\n\n- `git history split` allows you to split up a commit into two, which is\n  inspired by `jj split`. You give it a commit, Git asks you which changes to\n  stage into which commit and for the two commit messages, and then you're done.\n\n\nThis is of course only a start, and we want to add additional subcommands over time. For example:\n\n- `git history fixup` to take staged changes and automatically amend them to a\n  specific commit\n\n- `git history drop` to remove a commit\n- `git history reorder` to reorder the sequence of commits\n- `git history squash` to squash a range of commits\n\nBut that's not all! In addition to making history editing easy, this new command also knows to automatically rebase all of your local branches that previously included this commit. So that means that you can even edit a commit that is not on the current branch, and all branches that contain the commit will be rewritten.\n\nIt may seem puzzling at first that Git is automatically rebasing dependent branches, as that is a significant diversion from how git-rebase(1) works. But this is part of a bigger effort to bring better support for Stacked Diffs to Git, which are a way to create a series of multiple dependent branches that can be reviewed indepentently, but that together work towards a bigger goal.\n\n*This project was led by [Patrick Steinhardt](https://gitlab.com/pks-gitlab) with support from [Elijah Newren](https://github.com/newren).*\n\n## A native replacement for git-sizer(1)\n\nThe size of a Git repository is an important factor that determines how well Git and GitLab can handle it. But size alone is not the only factor, as the performance of a repository is ultimately a combination of multiple different dimensions:\n\n- The depth of the commit history\n- The shape of the directory structure\n- The size of files stored in the repository\n- The number of references\n\nThese are only some of the dimensions one needs to consider when trying to predict whether Git will be able to handle a repository well.\n\nBut while it is clear that the mere repository size is insufficient, Git itself does not provide any tooling that gives the user an easy overview of these metrics. Instead, users are forced to rely on third-party tools like [git-sizer(1)](https://github.com/github/git-sizer) to fill this gap. This tool does an excellent job at surfacing this information, but it is not part of Git itself and thus needs to be installed separately.\n\nObservability of repository internals is critical to us at GitLab, so we introduced a [new `git repo structure` command into Git 2.52](https://about.gitlab.com/blog/whats-new-in-git-2-52-0/#new-subcommand-for-git-repo1-to-display-repository-metrics) to display repository metrics, which we have extended in Git 2.53 to [show inflated and disk sizes for objects by type](https://about.gitlab.com/blog/whats-new-in-git-2-53-0/#more-data-collected-in-git-repo-structure).\n\nIn Git 2.54, we are now iterating some more on this command so that we don't only show the overall size, but also show the largest objects by type:\n\n```shell\n$ git clone https://gitlab.com/git-scm/git.git\n$ cd git\n$ git repo structure\nCounting objects: 410445, done.\n| Repository structure      | Value       |\n| ------------------------- | ----------- |\n| * References              |             |\n|   * Count                 |    1.01 k   |\n|     * Branches            |       1     |\n|     * Tags                |    1.00 k   |\n|     * Remotes             |       9     |\n|     * Others              |       0     |\n|                           |             |\n| * Reachable objects       |             |\n|   * Count                 |  410.45 k   |\n|     * Commits             |   83.99 k   |\n|     * Trees               |  164.46 k   |\n|     * Blobs               |  161.00 k   |\n|     * Tags                |    1.00 k   |\n|   * Inflated size         |    7.46 GiB |\n|     * Commits             |   57.53 MiB |\n|     * Trees               |    2.33 GiB |\n|     * Blobs               |    5.07 GiB |\n|     * Tags                |  737.48 KiB |\n|   * Disk size             |  181.37 MiB |\n|     * Commits             |   33.11 MiB |\n|     * Trees               |   40.58 MiB |\n|     * Blobs               |  107.11 MiB |\n|     * Tags                |  582.67 KiB |\n|                           |             |\n| * Largest objects         |             |\n|   * Commits               |             |\n|     * Maximum size    [1] |   17.23 KiB |\n|     * Maximum parents [2] |      10     |\n|   * Trees                 |             |\n|     * Maximum size    [3] |   58.85 KiB |\n|     * Maximum entries [4] |    1.18 k   |\n|   * Blobs                 |             |\n|     * Maximum size    [5] | 1019.51 KiB |\n|   * Tags                  |             |\n\n|     * Maximum size    [6] |    7.13 KiB |\n\n[1] f6ecb603ff8af608a417d7724727d6bc3a9dbfdf\n[2] 16d7601e176cd53f3c2f02367698d06b85e08879\n[3] 203ee97047731b9fd3ad220faa607b6677861a0d\n[4] 203ee97047731b9fd3ad220faa607b6677861a0d\n[5] aa96f8bc361fd84a1459440f1e7de02ab0dc3543\n[6] 07e38db6a5a03690034d27104401f6c8ea40f1fc\n```\n\nWith this information we're now almost feature-complete as compared to git-sizer(1). We're not done yet, though — we plan to eventually add additional features such as:\n\n- Severity levels as they exist in git-sizer(1)\n- Graphs that show you the distribution of object sizes\n- The ability to scan objects reachable via a subset of references\n\n*This project was led by [Justin Tobler](https://gitlab.com/justintobler).*\n\n## New infrastructure for repository maintenance\n\nWhenever you write data into a Git repository you will typically end up adding more loose objects. Left unmanaged, this leads to a large number of separate files in your `.git/objects/` directory, which slows down several operations that want to access many objects at once. Git thus regularly packs these objects into \"packfiles\" to ensure good performance.\n\nThis isn't the only data structure that may become inefficient over time: Updating references may create loose references, reflogs will need trimming, worktrees may become stale, and caches like commit-graphs need to be refreshed regularly.\n\nAll of these tasks have historically been managed by [git-gc(1)](https://git-scm.com/docs/git-gc). However, this tool has a monolithic architecture, where it basically executes all of the tasks required in sequential order. This foundation is hard to extend and doesn't give the end user much flexibility in case they want to slightly modify how housekeeping is performed.\n\nThe Git project introduced the new [git-maintenance(1)](https://git-scm.com/docs/git-maintenance) tool in Git 2.29. In contrast to git-gc(1), git-maintenance(1) is not monolithic but is instead structured around tasks. These tasks are freely configurable by the user so that the user can control which tasks are running, giving them much more fine-grained control over repository maintenance.\n\nEventually, Git has migrated to use git-maintenance(1) by default. But in the beginning, the only task that was default-enabled was the git-gc(1) task, which as you might have guessed, simply executes `git gc`. To manually run maintenance using this new command you can execute `git maintenance run`, but Git knows to execute this automatically after several other commands.\n\nOver the last couple releases we have implemented all the individual tasks that are supported by git-gc(1) in git-maintenance(1) to ensure that we have feature parity between these two tools.\n\nFurthermore, we have implemented a new task that uses Git's modern architecture for repacking objects with [geometric compaction](https://git-scm.com/docs/git-repack#Documentation/git-repack.txt---geometricfactor).\nGeometric compaction is a much better fit for large monorepos, and with our efforts to make them work well with partial clones [that landed in Git 2.53](https://about.gitlab.com/blog/whats-new-in-git-2-53-0/#geometric-repacking-support-with-promisor-remotes) they are now a full replacement for our previous repacking strategy in Git.\n\nIn Git 2.54, we have now reached another significant milestone: Instead of using the git-gc(1)-based strategy by default, we are now using geometric repacking with fine-grained individual maintenance tasks! Besides being more efficient for large monorepos, it also ensures that we have an easier foundation to iterate on going forward.\n\n*The git-maintenance(1) infrastructure was originally implemented by [Derrick Stolee](https://github.com/derrickstolee) and geometric maintenance was introduced by [Taylor Blau](https://github.com/ttaylorr). The effort to introduce the new fine-grained tasks and migrate to the new maintenance strategy was led by [Patrick Steinhardt](https://gitlab.com/pks-gitlab).*\n\n## Read more\n\nThis article highlighted just a few of the contributions made by GitLab and the wider Git community for this latest release. You can learn about these from the [official release announcement](https://lore.kernel.org/git/xmqqa4uxsjrs.fsf@gitster.g/T/#u) of the Git project. Also, check out our [previous Git release blog posts](https://about.gitlab.com/blog/tags/git/) to see other past highlights of contributions from GitLab team members.",{"slug":726,"featured":12,"template":13},"whats-new-in-git-2-54-0",{"content":728,"config":737},{"title":729,"description":730,"authors":731,"date":733,"body":734,"heroImage":735,"category":9,"tags":736},"What’s new in Git 2.53.0?","Learn about release contributions, including fixes for geometric repacking, updates to git-fast-import(1) commit signature handing options, and more.",[732],"Justin Tobler","2026-02-02","The Git project recently released [Git 2.53.0](https://lore.kernel.org/git/xmqq4inz13e3.fsf@gitster.g/T/#u). Let's look at a few notable highlights from this release, which includes\ncontributions from the Git team at GitLab.\n\n## Geometric repacking support with promisor remotes\n\nNewly written objects in a Git repository are often stored as individual loose files. To ensure good performance and optimal use of disk space, these loose objects are regularly compressed into so-called packfiles. The number of packfiles in a repository grows over time as a result of the user’s activities, like writing new commits or fetching from a remote. As the number of packfiles in a repository increases, Git has to do more work to look up individual objects. Therefore, to preserve optimal repository performance, packfiles are periodically repacked via git-repack(1) to consolidate the objects into fewer packfiles. When repacking there are two strategies: “all-into-one” and “geometric”.\n\nThe all-into-one strategy is fairly straightforward and the current default. As its name implies, all objects in the repository are packed into a single packfile. From a performance perspective this is great for the repository as Git only has to scan through a single packfile when looking up objects. The main downside of such a repacking strategy is that computing a single packfile for a repository can take a significant amount of time for large repositories.\n\nThe geometric strategy helps mitigate this concern by maintaining a geometric progression of packfiles based on their size instead of always repacking into a single packfile. To explain more plainly, when repacking Git maintains a set of packfiles ordered by size where each packfile in the sequence is expected to be at least twice the size of the preceding packfile. If a packfile in the sequence violates this property, packfiles are combined as needed until the progression is restored. This strategy has the advantage of still minimizing the number of packfiles in a repository while also minimizing the amount of work that must be done for most repacking operations.\n\nOne problem with the geometric repacking strategy was that it was not compatible with partial clones. Partial clones allow the user to clone only parts of a repository by, for example, skipping all blobs larger than 1 megabyte. This can significantly reduce the size of a repository, and Git knows how to backfill missing objects that it needs to access at a later point in time.\n\nThe result is a repository that is missing some objects, and any object that may not be fully connected is stored in a “promisor” packfile.  When repacking, this promisor property needs to be retained going forward for packfiles containing a promisor object so it is known whether a missing object is expected and can be backfilled from the promisor remote. With an all-into-one repack, Git knows how to handle promisor objects properly and stores them in a separate promisor packfile. Unfortunately, the geometric repacking strategy did not know to give special treatment to promisor packfiles and instead would merge them with normal packfiles without considering whether they reference promisor objects. Luckily, due to a bug the underlying git-pack-objects(1) dies when using geometric repacking in a partial clone repository. So this means repositories in this configuration were not able to be repacked anyways which isn’t great, but better than repository corruption.\n\nWith the release of Git 2.53, geometric repacking now works with partial clone repositories. When performing a geometric repack, promisor packfiles are handled separately in order to preserve the promisor marker and repacked following a separate geometric progression. With this fix, the geometric strategy moves closer towards becoming the default repacking strategy. For more information check out the corresponding [mailing list thread](https://lore.kernel.org/git/20260105-pks-geometric-repack-with-promisors-v1-0-c4660573437e@pks.im/).\n\nThis project was led by [Patrick Steinhardt](https://gitlab.com/pks-gitlab).\n\n## git-fast-import(1) learned to preserve only valid signatures\n\nIn our [Git 2.52 release article](https://about.gitlab.com/blog/whats-new-in-git-2-52-0/), we covered signature related improvements to git-fast-import(1) and git-fast-export(1). Be sure to check out that post for a more detailed explanation of these commands, how they are used, and the changes being made with regards to signatures.\n\nTo quickly recap, git-fast-import(1) provides a backend to efficiently import data into a repository and is used by tools such as [git-filter-repo(1)](https://github.com/newren/git-filter-repo) to help rewrite the history of a repository in bulk. In the Git 2.52 release, git-fast-import(1) learned the `--signed-commits=\u003Cmode>` option similar to the same option in git-fast-export(1). With this option, it became possible to unconditionally retain or strip signatures from commits/tags.\n\nIn situations where only part of the repository history has been rewritten, any signature for rewritten commits/tags becomes invalid. This means git-fast-import(1) is limited to either stripping all signatures or keeping all signatures even if they have become invalid. But retaining invalid signatures doesn’t make much sense, so rewriting history with git-repo-filter(1) results in all signatures being stripped, even if the underlying commit/tag is not rewritten. This is unfortunate because if the commit/tag is unchanged, its signature is still valid and thus there is no real reason to strip it. What is really needed is a means to preserve signatures for unchanged objects, but strip invalid ones.\n\nWith the release of Git 2.53, the git-fast-import(1) `--signed-commits=\u003Cmode>` option has learned a new `strip-if-invalid` mode which, when specified, only strips signatures from commits that become invalid due to being rewritten. Thus, with this option it becomes possible to preserve some commit signatures when using git-fast-import(1). This is a critical step towards providing the foundation for tools like git-repo-filter(1) to preserve valid signatures and eventually re-sign invalid signatures.\n\nThis project was led by [Christian Couder](https://gitlab.com/chriscool).\n\n## More data collected in git-repo-structure\n\nIn the Git 2.52 release, the “structure” subcommand was introduced to git-repo(1). The intent of this command was to collect information about the repository and eventually become a native replacement for tools such as [git-sizer(1)](https://github.com/github/git-sizer). At GitLab, we host some extremely large repositories, and having insight into the general structure of a repository is critical to understand its performance characteristics. In this release, the command now also collects total size information for reachable objects in a repository to help understand the overall size of the repository. In the output below, you can see the command now collects both the total inflated and disk sizes of reachable objects by object type.\n\n```shell\n$ git repo structure\n\n| Repository structure | Value      |\n| -------------------- | ---------- |\n| * References         |            |\n|   * Count            |   1.78 k   |\n|     * Branches       |      5     |\n|     * Tags           |   1.03 k   |\n|     * Remotes        |    749     |\n|     * Others         |      0     |\n|                      |            |\n| * Reachable objects  |            |\n|   * Count            | 421.37 k   |\n|     * Commits        |  88.03 k   |\n|     * Trees          | 169.95 k   |\n|     * Blobs          | 162.40 k   |\n|     * Tags           |    994     |\n|   * Inflated size    |   7.61 GiB |\n|     * Commits        |  60.95 MiB |\n|     * Trees          |   2.44 GiB |\n|     * Blobs          |   5.11 GiB |\n|     * Tags           | 731.73 KiB |\n|   * Disk size        | 301.50 MiB |\n|     * Commits        |  33.57 MiB |\n|     * Trees          |  77.92 MiB |\n|     * Blobs          | 189.44 MiB |\n|     * Tags           | 578.13 KiB |\n```\n\nThe keen-eyed among you may have also noticed that the size values in the table output are also now listed in a more human-friendly manner with units appended. In subsequent releases we hope to further expand this command's output to provide additional data points such as the largest individual objects in the repository.\n\nThis project was led by [Justin Tobler](https://gitlab.com/justintobler).\n\n## Read more\n\nThis article highlighted just a few of the contributions made by GitLab and\nthe wider Git community for this latest release. You can learn about these from\nthe [official release announcement](https://lore.kernel.org/git/xmqq4inz13e3.fsf@gitster.g/T/#u) of the Git project. Also, check\nout our [previous Git release blog posts](https://about.gitlab.com/blog/tags/git/)\nto see other past highlights of contributions from GitLab team members.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663087/Blog/Hero%20Images/git3-cover.png",[722,723,259],{"featured":27,"template":13,"slug":738},"whats-new-in-git-2-53-0",{"content":740,"config":749},{"title":741,"description":742,"authors":743,"heroImage":735,"date":746,"body":747,"category":9,"tags":748},"What’s new in Git 2.52.0?","Learn about release contributions, including the new git-last-modified(1) command, improvements to history-rewriting tools, and a new maintenance strategy.",[744,745,718],"Christian Couder","Toon Claes","2025-11-17","The Git project recently released [Git 2.52](https://lore.kernel.org/git/xmqqh5usmvsd.fsf@gitster.g/). After a relatively short 8-week [release cycle for 2.51](https://about.gitlab.com/blog/what-s-new-in-git-2-51-0/), due to summer in the Northern Hemisphere, this release is back to the usual 12-week cycle. Let’s look at some notable changes, including contributions from the GitLab Git team and the wider Git community.\n\n## New git-last-modified(1) command\n\nMany Git forges like GitLab display files in a tree view like this:\n\n\n| Name        | Last commit                                             | Last update  |\n| ------------- | --------------------------------------------------------- | -------------- |\n| README.md   | README: *.txt -> *.adoc fixes                           | 4 months ago |\n| RelNotes    | Start 2.51 cycle, the first batch                       | 4 weeks ago  |\n| SECURITY.md | SECURITY: describe how to report vulnerabilities        | 4 years      |\n| abspath.c   | abspath: move related functions to abspath              | 2 years      |\n| abspath.h   | abspath: move related functions to abspath              | 2 years      |\n| aclocal.m4  | configure: use AC_LANG_PROGRAM consistently             | 15 years ago |\n| add-patch.c | pager: stop using `the_repository`                      | 7 months ago |\n| advice.c    | advice: allow disabling default branch name advice      | 4 months ago |\n| advice.h    | advice: allow disabling default branch name advice      | 4 months ago |\n| alias.h     | rebase -m: fix serialization of strategy options        | 2 years      |\n| alloc.h     | git-compat-util: move alloc macros to git-compat-util.h | 2 years ago  |\n| apply.c     | apply: only write intents to add for new files          | 8 days ago   |\n| archive.c   | Merge branch 'ps/parse-options-integers'                | 3 months ago |\n| archive.h   | archive.h: remove unnecessary include                   | 1 year       |\n| attr.h      | fuzz: port fuzz-parse-attr-line from OSS-Fuzz           | 9 months ago |\n| banned.h    | banned.h: mark `strtok()` and `strtok_r()` as banned    | 2 years      |\n\n\n\u003Cbr>\u003C/br>\n\nNext to the files themselves, we also display which commit last modified each respective file. This information is easy to extract from Git by executing the following command:\n\n\n```shell\n\n$ git log --max-count=1 HEAD -- \u003Cfilename>\n\n```\n\nWhile nice and simple, this has a significant catch: Git does not have a way to extract this information for each of these files in a single command. So to get the last commit for all the files in the tree, we'd need to run this command for each file separately. This results in a command pipeline similar to the following:\n\n```shell\n\n$ git ls-tree HEAD --name-only | xargs --max-args=1 git log --max-count=1 HEAD --\n\n```\n\nNaturally, this isn't very efficient:\n\n\n* We need to spin up a fresh Git command for each file.\n\n\n* Git has to step through history for each file separately.\n\n\n\nAs a consequence, this whole operation is quite costly and generates significant load for GitLab.\n\n\n\nTo overcome these issues, a new Git subcommand `git-last-modified(1)` has been introduced. This command returns the commit for each file of a given commit:\n\n\n\n```shell\n\n$ git last-modified HEAD\n\n\ne56f6dcd7b4c90192018e848d0810f091d092913        add-patch.c\n373ad8917beb99dc643b6e7f5c117a294384a57e        advice.h\ne9330ae4b820147c98e723399e9438c8bee60a80        advice.c\n5e2feb5ca692c5c4d39b11e1ffa056911dd7dfd3        alloc.h\n954d33a9757fcfab723a824116902f1eb16e05f7        RelNotes\n4ce0caa7cc27d50ee1bedf1dff03f13be4c54c1f        apply.c\n5d215a7b3eb0a9a69c0cb9aa43dcae956a0aa03e        archive.c\nc50fbb2dd225e7e82abba4380423ae105089f4d7        README.md\n72686d4e5e9a7236b9716368d86fae5bf1ae6156        attr.h\nc2c4138c07ca4d5ffc41ace0bfda0f189d3e262e        archive.h\n5d1344b4973c8ea4904005f3bb51a47334ebb370        abspath.c\n5d1344b4973c8ea4904005f3bb51a47334ebb370        abspath.h\n60ff56f50372c1498718938ef504e744fe011ffb        banned.h\n4960e5c7bdd399e791353bc6c551f09298746f61        alias.h\n2e99b1e383d2da56c81d7ab7dd849e9dab5b7bf0        SECURITY.md\n1e58dba142c673c59fbb9d10aeecf62217d4fc9c        aclocal.m4\n```\n\n\n\nThe benefit of this is obviously that we only have to execute a single Git process now to derive all of that information. But even more importantly, it only requires us to walk the history once for all files together instead of having to walk it multiple times. This is achieved by:\n\n\n1. Start walking the history from the specified commit.\n\n\n2. For each commit:\n   1. If it doesn't modify any of the paths we're interested in we continue to the next commit.\n   2. If it does, we print the commit ID together with the path. Furthermore, we remove the path from the set of interesting paths.\n3. When the list of interesting paths becomes empty we stop.\n\n\n\nGitaly has already been adjusted to use the new command, but the logic is still guarded by a feature flag. Preliminary testing has shown that `git-last-modified(1)` is in most situations at least twice as fast compared to using `git log --max-count=1`.\n\n\n\n*These changes were [originally written](https://github.com/ttaylorr/git/tree/tb/blame-tree) by multiple developers from GitHub and were [upstreamed](https://lore.kernel.org/git/20250805093358.1791633-1-toon@iotcl.com/) into Git by [Toon Claes](https://gitlab.com/toon).*\n\n\n\n## git-fast-export(1) and git-fast-import(1) signature-related improvements\n\n\n\nThe `git-fast-export(1)` and `git-fast-import(1)` commands are designed to be mostly used by interoperability or history rewriting tools. The goal of interoperability tools is to make Git interact nicely with other software, usually a different version control system, that stores data in a different format than Git. For example [hg-fast-export.sh](https://github.com/frej/fast-export) is a “Mercurial to Git converter using git-fast-import.\"\n\n\n\nAlternately, history-rewriting tools let users — usually admins — make changes to the history of their repositories that are not possible or not allowed by the version control system. For example, [reposurgeon](http://www.catb.org/esr/reposurgeon/) says in its [introduction](https://gitlab.com/esr/reposurgeon/-/blob/master/repository-editing.adoc?ref_type=heads#introduction) that its purpose is “to enable risky operations that version-control systems don't want to let you do, such as (a) editing past comments and metadata, (b) excising commits, (c) coalescing and splitting commits, (d) removing files and subtrees from repo history, (e) merging or grafting two or more repos, and (f) cutting a repo in two by cutting a parent-child link, preserving the branch structure of both child repos.\"\n\n\n\nWithin GitLab, we use [git-filter-repo](https://github.com/newren/git-filter-repo) to let admins perform some risky operations on their Git repositories. Unfortunately, until Git 2.50 (released last June), both `git-fast-export(1)` and `git-fast-import(1)` didn't handle cryptographic commit signatures at all. So, although `git-fast-export(1)` had a `--signed-tags=\u003Cmode>` option that allows users to change how cryptographic tag signatures are handled, commit signatures were simply ignored.\n\n\n\nCryptographic signatures are very fragile because they are based on the exact commit or tag data that was signed. When the signed data or any of its preceding history changes, the cryptographic signature becomes invalid. This is a fragile but necessary requirement to make these signatures useful.\n\n\n\nBut in the context of rewriting history this is a problem:\n\n\n\n* We may want to keep cryptographic signatures for both commits and tags that are still valid after the rewrite (e.g. because the history leading up to them did not change).\n\n\n* We may want to create new cryptographic signatures for commits and tags where the previous signature has become invalid.\n\n\n\nNeither `git-fast-import(1)` nor `git-fast-export(1)` allow for these use cases though, which limits what tools like [git-filter-repo](https://github.com/newren/git-filter-repo) or [reposurgeon](http://www.catb.org/esr/reposurgeon/) can achieve.\n\n\n\nWe have made some significant progress:\n\n\n\n* In Git 2.50 we added a `--signed-commits=\u003Cmode>` option to `git-fast-export(1)` for exporting commit signatures, and support in `git-fast-import(1)` for importing them.\n\n\n* In Git 2.51 we improved the format used for exporting and importing commit signatures, and we made it possible for `git-fast-import(1)` to import both a signature made on the SHA-1 object ID of the commit and one made on its SHA-256 object ID.\n\n\n* In Git 2.52 we added the `--signed-commits=\u003Cmode>` and `--signed-tags=\u003Cmode>` options to `git-fast-import(1)`, so the user has control over how to handle signed data at import time.\n\n\n\nThere is still more to be done. We need to add the ability to:\n\n\n\n* Retain only those commit signatures that are still valid to `git-fast-import(1)`.\n\n\n* Re-sign data where the signature became invalid.\n\n\n\nWe have already started to work on these next steps and expect this to land in Git 2.53. Once done, tools like `git-filter-repo(1)` will finally start to handle cryptographic signatures more gracefully. We will keep you posted in our next Git release blog post.\n\n\n\n*This project was led by [Christian Couder](https://gitlab.com/chriscool).*\n\n\n\n## New and improved git-maintenance(1) strategies\n\n\n\nGit repositories require regular maintenance to ensure that they perform well. This maintenance performs a bunch of different tasks: references get optimized, objects get compressed, and stale data gets pruned.\n\n\n\nUntil Git 2.28, these maintenance tasks were performed by `git-gc(1)`. The problem with this command is that it wasn't built with customizability in mind: While certain parameters can be configured, it is not possible to control which parts of a repository should be optimized. This means that it may not be a good fit for all use cases. Even more importantly, it made it very hard to iterate on how exactly Git performs repository maintenance.\n\n\n\nTo fix this issue and allow us to iterate again, [Derrick Stolee](https://github.com/derrickstolee) introduced `git-maintenance(1)`. In contrast to `git-gc(1),` it is built with customizability in mind and allows the user to configure which tasks specifically should be running in a certain repository. This new tool was made the default for Git’s automated maintenance in Git 2.29, but, by default, it still uses `git-gc(1)` to perform the maintenance.\n\n\n\nWhile this default maintenance strategy works well in small or even medium-sized repositories, it is problematic in the context of large monorepos. The biggest limiting factor is how `git-gc(1)` repacks objects: Whenever there are more than 50 packfiles, the tool will merge all of them together into a single packfile. This operation is quite CPU-intensive and causes a lot of I/O operations, so for large monorepos this operation can easily take many minutes or even hours to complete.\n\n\n\nGit already knows how to minimize these repacks via “geometric repacking.” The idea is simple: The packfiles that exist in the repository must follow a geometric progression where every packfile must contain at least twice as many objects as the next smaller one. This allows Git to amortize the number of repacks required while still ensuring that there is only a relatively small number of packfiles overall. This mode was introduced by [Taylor Blau](https://github.com/ttaylorr) in Git 2.32, but it was not wired up as part of the automated maintenance.\n\n\n\nAll the parts exist to make repository maintenance way more scalable for large monorepos: We have the flexible `git-maintenance(1)` tool that can be extended to have a new maintenance strategy, and we have a better way to repack objects. All that needs to be done is to combine these two.\n\n\n\nAnd that's exactly what we did with Git 2.52! We have introduced a new “geometric” maintenance strategy that you can configure in your Git repositories. This strategy is intended as a full replacement for the old strategy based on `git-gc(1)`. Here is the config code you need:\n\n\n\n```shell\n\n$ git config set maintenance.strategy geometric\n\n```\n\n\n\nFrom hereon, Git will use geometric repacking to optimize your objects. This should lead to less churn while ensuring that your objects are in a better-optimized state, especially in large monorepos.\n\n\n\nIn Git 2.53, we aim to make this the default strategy. So stay tuned!\n\n\n\n*This project was led by [Patrick Steinhardt](https://gitlab.com/pks-gitlab).*\n\n\n\n## New subcommand for git-repo(1) to display repository metrics\n\n\n\nPerformance of Git operations in a repository are often dependent on certain characteristics of its underlying structure. At GitLab, we host some extremely large repositories and having insight into the general structure of a repository is critical to understand performance. While it is possible to compose various Git commands and other tools together to surface certain repository metrics, Git lacks a means to surface info about a repository's shape/structure via a single command. This has led to the development of other external tools, such as [git-sizer(1)](https://github.com/github/git-sizer), to fill this gap.\n\n\n\nWith the release of Git 2.52, a new “structure” subcommand has been added to git-repo(1) with the aim to surface information about a repository's structure. Currently, it displays info about the number of references and objects in the repository in the following form:\n\n\n\n```shell\n\n$ git repo structure\n\n\n| Repository structure | Value  |\n| -------------------- | ------ |\n| * References         |        |\n|   * Count            |   1772 |\n|     * Branches       |      3 |\n|     * Tags           |   1025 |\n|     * Remotes        |    744 |\n|     * Others         |      0 |\n|                      |        |\n| * Reachable objects  |        |\n|   * Count            | 418958 |\n|     * Commits        |  87468 |\n|     * Trees          | 168866 |\n|     * Blobs          | 161632 |\n|     * Tags           |    992 |\n\n```\n\n\n\nIn subsequent releases we hope to expand on this and provide other interesting data points like the largest objects in the repository.\n\n\n\n*This project was led by [Justin Tobler](https://gitlab.com/justintobler).*\n\n\n\n## Improvements related to the Google Summer of Code 2025\n\n\n\nWe had three successful projects with the Google Summer of Code.\n\n\n\n### Refactoring in order to reduce Git's global state\n\n\n\nGit contains several global variables used throughout the codebase. This increases the complexity of the code and reduces the maintainability. As part of this project, [Ayush Chandekar](https://ayu-ch.github.io/) worked on reducing the usage of the `the_repository` global variable via a series of patches.\n\n\n\n*The project was mentored by [Christian Couder](https://gitlab.com/chriscool) and [Ghanshyam Thakkar](https://in.linkedin.com/in/ghanshyam-thakkar).*\n\n\n\n### Machine-readable Repository Information Query Tool\n\n\n\nGit lacks a centralized way to retrieve repository information, requiring users to piece it together from various commands. While `git-rev-parse(1)` has become the de-facto tool for accessing much of this information, doing so falls outside its primary purpose.\n\n\n\nAs part of this project, [Lucas Oshiro](https://lucasoshiro.github.io/en/) introduced a new command, `git-repo(1),` which will house all repository-level information. Users can now use `git repo info` to obtain repository information:\n\n\n\n```shell\n\n$ git repo info layout.bare layout.shallow object.format references.format\n\nlayout.bare=false\nlayout.shallow=false\nobject.format=sha1\nreferences.format=reftable\n\n```\n\n\n\n*The project was mentored by [Patrick Steinhardt](https://gitlab.com/pks-gitlab) and [Karthik Nayak](https://gitlab.com/knayakgl).*\n\n\n\n### Consolidate ref-related functionality into git-refs\n\n\n\nGit offers multiple commands for managing references, namely `git-for-each-ref(1)`, `git show-ref(1)`, `git-update-ref(1)`, and `git-pack-refs(1)`. This makes them harder to discover and creates overlapping functionality. To address this, we introduced the `git-refs(1)` command to consolidate these operations under a single interface. As part of this this project, [Meet Soni](https://inosmeet.github.io/) extended the command by adding the following subcommands:\n\n\n\n* `git refs optimize` to optimize the reference backend\n\n\n* `git refs list` to list all references\n\n\n* `git refs exists` to verify the existence of a reference\n\n\n\n*The project was mentored by [Patrick Steinhardt](https://gitlab.com/pks-gitlab) and [shejialuo](https://luolibrary.com/).*\n\n\n\n## What's next?\n\n\n\nReady to experience these improvements? Update to Git 2.52.0 and start using `git last-modified`.\n\n\n\nAt GitLab, we will of course ensure that all of these improvements will eventually land in a GitLab instance near you!\n\n\n\nLearn more in the [official Git 2.52.0 release notes](https://lore.kernel.org/git/xmqqh5usmvsd.fsf@gitster.g/) and explore our [complete archive of Git development coverage](https://about.gitlab.com/blog/tags/git/).\n",[722,723,259],{"featured":27,"template":13,"slug":750},"whats-new-in-git-2-52-0",{"promotions":752},[753,767,779,791],{"id":754,"categories":755,"header":757,"text":758,"button":759,"image":764},"ai-modernization",[756],"ai-ml","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":760,"config":761},"Get your AI maturity score",{"href":762,"dataGaName":763,"dataGaLocation":241},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":765},{"src":766},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":768,"categories":769,"header":771,"text":758,"button":772,"image":776},"devops-modernization",[770,567],"product","Are you just managing tools or shipping innovation?",{"text":773,"config":774},"Get your DevOps maturity score",{"href":775,"dataGaName":763,"dataGaLocation":241},"/assessments/devops-modernization-assessment/",{"config":777},{"src":778},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":780,"categories":781,"header":783,"text":758,"button":784,"image":788},"security-modernization",[782],"security","Are you trading speed for security?",{"text":785,"config":786},"Get your security maturity score",{"href":787,"dataGaName":763,"dataGaLocation":241},"/assessments/security-modernization-assessment/",{"config":789},{"src":790},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":792,"paths":793,"header":796,"text":797,"button":798,"image":803},"github-azure-migration",[794,795],"migration-from-azure-devops-to-gitlab","integrating-azure-devops-scm-and-gitlab","Is your team ready for GitHub's Azure move?","GitHub is already rebuilding around Azure. Find out what it means for you.",{"text":799,"config":800},"See how GitLab compares to GitHub",{"href":801,"dataGaName":802,"dataGaLocation":241},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":804},{"src":778},{"header":806,"blurb":807,"button":808,"secondaryButton":813},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":809,"config":810},"Get your free trial",{"href":811,"dataGaName":48,"dataGaLocation":812},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":503,"config":814},{"href":52,"dataGaName":53,"dataGaLocation":812},1777302615223]