[{"data":1,"prerenderedAt":720},["ShallowReactive",2],{"/en-us/blog/better-code-reviews/":3,"navigation-en-us":36,"banner-en-us":465,"footer-en-us":482,"David O'Regan":691,"next-steps-en-us":705},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"seo":8,"content":16,"config":26,"_id":29,"_type":30,"title":31,"_source":32,"_file":33,"_stem":34,"_extension":35},"/en-us/blog/better-code-reviews","blog",false,"",{"title":9,"description":10,"ogTitle":9,"ogDescription":10,"noIndex":6,"ogImage":11,"ogUrl":12,"ogSiteName":13,"ogType":14,"canonicalUrls":12,"schema":15},"Better Code Reviews GitLab Style","Better Code Reviews - A selection of tools for your tool-belt when it comes to code reviews.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1749663502/Blog/Hero%20Images/paperclips.jpg","https://about.gitlab.com/blog/better-code-reviews","https://about.gitlab.com","article","\n                        {\n        \"@context\": \"https://schema.org\",\n        \"@type\": \"Article\",\n        \"headline\": \"Better Code Reviews GitLab Style\",\n        \"author\": [{\"@type\":\"Person\",\"name\":\"David O'Regan\"}],\n        \"datePublished\": \"2020-06-08\",\n      }",{"title":9,"description":10,"authors":17,"heroImage":11,"date":19,"body":20,"category":21,"tags":22},[18],"David O'Regan","2020-06-08","{::options parse_block_html=\"true\" /}\n\n\n\n\n> A love letter to anyone that's ever reviewed or been reviewed.\n\n\nThis blog post originally started as a thank-you message inside the GitLab\nslack channel `#thanks`, however, the scope of the message grew to such a\ndegree that I wanted to take it a step further and see if I could not only\nthank the amazing people this post is dedicated to, but also hopefully share\nsome of the amazing things they taught me to help *you*, dear reader.\n\n\nI have always been rather passionate about feedback. For as long as I can\nremember, I have always sought feedback on everything I was interested in.\nIt's as true for me in software as it is for my non computer related hobbies\nlike bodybuilding or grammar.....**cough cough**. Feedback is so important\nfor every aspect of life, and in software it is no different. Feedback\nmatters and in GitLab, we deliver most if not all of our feedback to one\nanother via the code review.\n\n\nThis post is designed to deliver a selection of the most fantastic things I\nhave seen in code reviews here at GitLab, with two goals:\n\n\n1. Acknowledge the people who work hard to ensure the feedback cycle they\nprovide is as good as it can be, because at GitLab we like to [say\nthanks](https://handbook.gitlab.com/handbook/values/#say-thanks).\n\n1. Offer you, the reader, a selection of tools for your toolbelt when it\ncomes to code reviews.\n\n\nEnter - **Better Code Reviews**.\n\n\n## Self Reviews - Details Matter\n\n\n> Before assigning MRs to the reviewer I practice a self-review to help the\nreviewer and the maintainer understand quirks and caveats of the MR. I am\ntrying to anticipate their concerns/questions. As a maintainer I find it\nalso very valuable. - Peter Leitzen\n([@splattael](https://gitlab.com/splattael))\n\n\nWe often take for granted that details are hard. Moreover, we often take for\ngranted that details in software are even harder. The majority of software\nconsists of layers upon layers of deep abstractions and obscure logic that\ncan be difficult, if not impossible, to really understand without spending a\nsignificant amount of time parsing it line by line.\n\n\nThis process is made even harder when the details or context are incorrect.\nThough it's natural for this to happen, humans are not spell checkers, nor\ndo the majority of us like to revisit a piece of work a fourth or fifth time\nto ensure it's as correct as it can be. If we all did this, nothing would\never be delivered.\n\n\nBut - there is a sweet spot to be found for this dilemma in software where\nwe can keep the velocity of delivery high, and also reduce the feedback\ncycle time through a small amount of dedicated effort to the details. We\ntalk about some of the details [here in the responsibility of the merge\nrequest\nauthor](https://docs.gitlab.com/ee/development/code_review.html#the-responsibility-of-the-merge-request-author).\n\n\nFor the merge request author, step through a checklist. Here is mine. If you\ncan't read my chicken-scratch handwriting, I'll type it out too:\n\n\n![merge-checklist](https://about.gitlab.com/images/blogimages/merge-checklist.png)\n\n\nBefore every feedback cycle:\n\n\n- Re-read every line\n\n- Test your code locally\n\n- Write a test for every change (or as many as you can)\n\n- Write a clear description and update it after each feedback cycle\n\n- Include at least one screenshot per change. More is better\n\n- Check, re-check and re-check your labels\n\n- Consider using a `~\"workflow::refinement\"` label for issues ahead of time\nlike we do in the Monitor:Health team\n\n- Review the code as if you were the reviewer. Be proactive, answer the\nlikely questions, and open followup issues ahead of time\n\n\nIf you want to see the last and most important part in action, check out one\nof our frontend maintainers Natalia\nTepluhina([@ntepluhina](https://gitlab.com/ntepluhina)) pre-answer a\nquestion she knew would be asked in [one of her merge\nrequests](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/33587#note_353564612).\n\n\n## Conventional Comments - Communicate Intent\n\n\n>  **Shaming** This is horrible code. How about re-writing all of it so that\nit stops being that bad? - Frédéric Caplette\n([@f_caplette](https://gitlab.com/f_caplette))\n\n\nOne of the hardest parts of getting a code review right is communicating the\nhuman touch. When we offer feedback and receive feedback, human habit\ncreates cognitive distortion by defaulting to the most negative aspects of\nthat feedback. At GitLab, we try to highlight that in our [value\nsystem](https://handbook.gitlab.com/handbook/values/#assume-positive-intent).\n\n\nIn the world of psychology, this is called **mental filtering**, and it's\nsomething that all humans have a tendency to do. Though in software this\naffliction can be more common, as working in software goes hand-in-hand with\nvaluing yourself based on how intelligent others think you are.\n\n\nEnter [conventional comments](https://conventionalcomments.org/) by Paul\nSlaughter ([@pslaughter](https://gitlab.com/pslaughter)) - a well\nthought-out system for leaving comments in a useful way for both the\nreviewer and author of the merge request. It's so popular one amazing person\nmade a [browser extension (chrome,\nfirefox)](https://gitlab.com/conventionalcomments/conventional-comments-button)\nfor it!\n\n\nSo why does adding a single bolded word to the top of a comment help with\nthe human touch? Well, it's all about intent.\n\n\nWhen you start the comment with an eye-catching single word that defines the\nintent and tone for the comment, it gives the reader a chance to understand\nwhere your comment is coming from.\n\n\nLet's try an experiment. If you had submitted code for review, which comment\nwould you prefer to read?\n\n\nOption one:\n\n\n```bash\n\nWhat do you think about X instead?\n\n```\n\n\nor option two:\n\n\n```bash\n\n**suggestion (non-blocking)**\n\n\nWhat do you think about X instead?\n\n```\n\n\nNow if you're anything like me, you took a preference to option two. It had\ncontext, communicated empathy, and was an invitation to try something\ndifferent rather than a command.\n\n\nThe magic part of this comment is the first line `**suggestion\n(non-blocking)**`. Straightaway, before you even read the comment, you know\nthe two most important things about it:\n\n\n1. It's a suggestion from the reviewer\n\n1. It's non-blocking, communicating it's more of a friendly suggestion then\na hard change that's needed\n\n\nAnother massive advantage this style of commenting has: it allows merge\nrequest authors to understand the reviewer is neither trying to block nor\nact as a gatekeeper for their work. By highlighting what counts as a\nblocking and a non-blocking comment, merge authors get the full context of\nwhat the reviewer is trying to communicate.\n\n\nTo demonstrate this, let's try another thought experiment! You have\nsubmitted a merge request for review and your review comes back with eight\ncomments.\n\n\n- **Scenario A: No context in comments.** All comments are treated equally\nbecause they lack context for what counts as a blocker and what doesn't.\n\n- **Scenario B:** Context added via conventional comments system.\n\n\nThe comments can be treated via priority:\n\n\n1. Blockers => What's needed to get the merge over the line.\n\n1. Non-blockers => What can be a separate merge or perhaps a discussion.\n\n\nNext time you're reviewing code, try using conventional comments and watch\nhow it affects not only the way the merge request author feels about the\nreview, but the way **you**, the reviewer, feel leaving the review. My guess\nis you'll feel a lot better.\n\n\nWe're currently looking at [integrating this feature directly into\nGitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/26891) because we\nbelieve in making GitLab the best possible place for code reviews, and want\nyou to have the best experience possible.\n\n\nIf you want to see a real-life example of some of Paul Slaughter's\n([@pslaughter](https://gitlab.com/pslaughter)) awesome work using\nconventional comments, check out [his reviews of my community\ncontributions](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/24897)\nhere at GitLab. That empathy shines through.\n\n\n## The Patch File\n\n\n> Here's a patch file to better explain - Denys Mishunov\n([@dmishunov](https://gitlab.com/dmishunov))\n\n\nWanna know a `git` secret? Patch files are the stuff of magic. If you want\nto read about them, [check the Git documentation for\npatches](https://git-scm.com/docs/git-format-patch).\n\n\n### How To Make A Patch File\n\n\nYou can make a patch file via your editor, or via the command line.\n\n\n#### Via The Editor\n\n\nRocking a nice fancy IDE or text editor? Most of them support patch files\nvia plugins, or out of the box!\n\n\n- [VSCode](https://github.com/paragdiwan/vscode-git-patch)\n\n- [Webstorm](https://www.jetbrains.com/help/webstorm/using-patches.html)\n\n- [Atom](https://atom.io/packages/git-plus)\n\n- [Vim](https://vim.fandom.com/wiki/How_to_make_and_submit_a_patch) …life is\nwhat happens when you're trying to exit `vim`?\n\n\n#### Via The CLI\n\n\nOkay, you’ve made some commits, here’s your `git log`:\n\n\n```plaintext\n\ngit log --pretty=oneline -3\n\n* da33d1k - (feature_branch) Reviewer Commit 1 (7 minutes ago)\n\n* 66a84ah - (feature_branch) Developer 1 Commit (12 minutes ago)\n\n* adsc8cd - (REL-0.5.0, origin/master, origin/HEAD, master) Release 13.0 (2\nweeks ago)\n\n```\n\n\nThis command creates a new file, `reviewer_commit.patch`, with all changes\nfrom the reviewer's latest commit against the feature branch:\n\n\n```plaintext\n\ngit format-patch HEAD~1 --stdout > reviewer_commit.patch\n\n```\n\n\n### Apply The Patch\n\n\nFirst, take a look at what changes are in the patch. You can do this easily\nwith `git apply`:\n\n\n```plaintext\n\ngit apply --stat reviewer_commit.patch\n\n```\n\n\nJust a heads up! Despite the name, this command won't actually apply the\npatch. It will just show the statistics about what the patch will do.\n\n\nSo now that we've had a look, let's test it first, because not all patches\nare created equal:\n\n\n```plaintext\n\ngit apply --check reviewer_commit.patch\n\n```\n\n\nNo errors? Awesome! We can apply this patch without worry.\n\n\nTo apply the patch, you should use `git am` instead of `git apply`. The\nreason: `git am` allows you to sign off an applied patch with the reviewer's\nstamp.\n\n\n```plaintext\n\ngit am --signoff \u003C reviewer_commit.patch\n\nApplying: Reviewer Commit 1\n\n```\n\n\nNow run `git log` and you can see the `Signed-off-by` tag in the commit\nmessage. This tag makes it very easy to understand how this commit ended up\nin the code base.\n\n\n### Why to use them in code reviews\n\n\nSo now that you know how to make a shiny patch file, why would you use patch\nfiles as part of a code review process? There are a few reasons you might\nconsider offering a patch file for a change you feel strongly about:\n\n\n1. It communicates you have invested a large amount of effort into\nunderstanding the author's solution and reasoning\n\n1. It demonstrates passion for reaching the best solution through teamwork\n\n1. It offers a willingness on the reviewer's part to accept responsibility\nfor this merge past the point of just reading the code\n\n\nSome people might argue patch files are a cheeky way for a reviewer to force\na change they would rather see make it into the code base, but I argue that\nanyone who has taken the time to check out a branch, run the project,\nimplement a change, and then submit that change back for a discussion is\nembodying the value of collaboration to the fullest.\n\n\nWant to see a awesome example of a patch file in action? Check out one of\nour frontend maintainers Denys Mishunov\n([@dmishunov](https://gitlab.com/dmishunov)) in action using a [patch file\nto its maximum\npotential](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/31686#note_341534370)!\n\n\nWe believe so much in creating the best code review experience here at\nGitLab, we're looking into how can we make this system a [seamless part of\nthe merge request and code review\nflow](https://gitlab.com/gitlab-org/gitlab/-/issues/220044).\n\n\n## Fairness\n\n\n> Fairness is a person's ability to rise above their own prejudice.\n\n\nFairness is a odd word. Chris Voss, a former FBI negotiator, said in his\nbook [Never Split The\nDifference](https://www.goodreads.com/book/show/26156469-never-split-the-difference)\nthat:\n\n\n> “Fair”—the most powerful word in any negotiation scenario. To become a\ngreat negotiator, you must earn the reputation of being a fair one.\n\n\nCode reviews can be viewed as a negotiation. It's you and another human\nbeing having a negotiation, based upon the idea that at the end, the result\nof this negotiation should be a selection of code that is both of value and\nof a high standard. While you might think that FBI negotiations and code\nreviews have little to do with one another, the concept being a fair\nnegotiator often can be the most useful tool in your toolbox as both an\nauthor and reviewer.\n\n\nYou can actually see it mentioned twice in the [permissions to play in\npoints 2 and 7](https://handbook.gitlab.com/handbook/values/#permission-to-play) guidelines here at\nGitLab:\n\n\n- \"Be dependable, reliable, fair, and respectful.\"\n\n- \"Seek out ways to be fair to everyone.\"\n\n\n### Author Fairness\n\n\nBeing fair as an author is the easier of the two. When you think of being\nfair as an author you need to adhere to a few simple Do's and Don'ts:\n\n\nDo:\n\n- Write a proper description with screenshots (can't stress this one enough)\n\n- Understand a reviewers point of view when they make suggestions\n\n- Pre-address strange parts of your merge (we all have them)\n\n- Be open to [collaboration](https://handbook.gitlab.com/handbook/values/#collaboration) on your work\n\n\nDon't:\n\n- \"plz merge\"\n\n- Forget to write a description with screenshots\n\n- Be closed off or take offense to suggestions\n\n- Forget to include any steps needed to get the build running or in other\nwords(reduce burden where possible!)\n\n\nHonestly, it's pretty simple to be a fair author of a merge request if you\nuse a small amount of empathy and remember that the person reviewing your\ncode **gets nothing extra** for their time spend reviewing their code. They\njust want to help take your merge to the next level.\n\n\n### Reviewer Fairness\n\n\nBeing fair as a reviewers is a tad harder than being fair as an author. But\nwhy, I hear you ask? The issue is something called \"bias\" - or\n[unconscious-bias](https://handbook.gitlab.com/handbook/values/#unconscious-bias), as the handbook\ndefines it.\n\n\nBias is, for better or for worse, something we all deal with when it comes\nto how we *want* things to be. We all have our own styles, preferences, and\nideas on how software should be written:\n\n\n> Eslint be damned I want you to use double quotes!\n\n\nThis creates issues when it comes to code reviews, because it's normal for a\nlot of your own bias to bleed into a comment. You begin thinking in\nabsolutes and the unresolved discussion count rises.\n\n\nLet me ask you something. Have you ever reviewed a merge request and found\nyourself saying things like:\n\n\n- \"It should be written like this?\"\n\n- \"Why would they do it like that?\"\n\n- \"I would have done it *this* way.\"\n\n- \"That's not how that should be done!\"\n\n\nWell, my friends, welcome to another common cognitive distortion called\n\"Should/must statements\". Do you want to be a better code reviewer? The next\ntime you write a comment and it includes the word \"should\" or \"must\", pause\nright there and really think about why you felt the need to use that word.\nSometimes it will be fair and warranted - such as if your company follows a\nset of coding conventions like we do at GitLab - but stay vigilant for when\nthose statements are a thin veil for a personal preference. Ask yourself if\nyou're being fair with your review. As a reviewer, if you find yourself in\nneed of using a should/must statement, be sure to supply a reference to\nsupporting documentation that is driving your statement.\n\n\nOne lesson I have learned through my own experience is that there is almost\nalways a reason for something to be done the way it is. The fair response to\nsomething you don't agree with is to ask *why* it's being done like that,\nnot saying it *must* be another way. That is how you become a fair and great\nnegotiator.\n\n\n## The Follow Up\n\n\n> I feel like the follow up issue should become a first class citizen. -\nSarah Yasonik ([@syasonik](https://gitlab.com/syasonik))\n\n\nLong merges suck. They just do. And while the concept of \"big doesn't always\nmean good\" might have started with food, it bleeds into the world of\nsoftware development through merge requests that are too big. They also\ndirectly conflict one of our [main\nvalues](https://handbook.gitlab.com/handbook/values/#make-small-merge-requests) of iteration. In\nGitLab, we take this so seriously that [Danger\nBot](https://docs.gitlab.com/ee/development/dangerbot.html) will ask you to\nbreak down merges that are over a certain size, helping developers champion\nthe [value of\niteration](https://handbook.gitlab.com/handbook/values/#iteration).\n\n\nLarge merge requests create huge amounts of complexity, they're hard to\ntest, they're hard to reason about, they hard to maintain or extend.....and\nthat's just for the author!\n\n\nSo what's worse than a large merge request? Reviewing a large merge request.\nIf you've ever been pinged to review a merge request that was longer than\n1000 lines, you understand what I am talking about. If it hasn't happened to\nyou yet, count your lucky stars that your teammates live and breathe some\ngood habits like simple solutions and iteration, and value a lack of\ncomplexity.\n\n\nThis creates a bigger problem than a complex reading exercise for the\nreviewer: it creates a context block. When a review grows past a certain\namount of lines, it simply becomes too difficult to reason about without\nchecking out the branch, booting the project and smoke testing. While smoke\ntesting complex reviews are a great idea, it should **not** become the\ndefault ideal for reviewing.\n\n\nIf the merge request is too long, the code review is too complex / too long.\nThe code rots, your merge conflicts grow, you can't iterate, you're\nconstantly addressing breaking conflicts … and you're stuck for days, maybe\nweeks, maybe forever.\n\n\nSo how do we fix this? In the Monitor:Health team's iteration retrospective,\nmy teammate Sarah Yasonik ([@syasonik](https://gitlab.com/syasonik)) raised\na point where she suggested the follow up issue / merge become a first class\ncitizen. I thought she was onto something amazing. If your merge is too\nlong, or your reviews are taking too long, break your merge down, keep the\nreviews small, and offer follow-ups.\n\n\nTreat the follow-up merge as a first-class citizen. Do it right there *while\nreading the reviewer's feedback* instead of adding more code to a already\ntoo big merge! Do **not** make a already bloated merge even worse by adding\nmore scope. Divide and conquer where possible.\n\n\nI think a lot of developers and reviewers find this process difficult\nbecause it's a contract of faith: \n\n\n- I, the author, promise to deliver a follow-up.\n\n- I, the reviewer, put myself on the line by taking your word that you will\nin fact fix this issue later.\n\n\nIt's scary, and lacks polish. I get it, but you should never let tomorrow's\nperfect stop today's progress because - spoiler alert - tomorrow isn't here,\nand we really only have today.\n\n\n### The Author Follow Up\n\n\nIf you offer a follow up, deliver it. It's your only rule but you cannot\nbreak it. Your credit for wilding the follow up resides solely in your\nconsistent ability to deliver on your promises over time. As a author you\nshould also work with your PMs and EMs to help prioritize the follow up as\npart of a wider team effort.\n\n\n### The Reviewer Follow Up\n\n\n- If you are offered a follow up, accept it with grace and trust the\ndeveloper to make good on their promise.\n\n- Be open to suggesting follow ups as part of your review.\n\n- Be patient with people.\n\n- Allow for wiggle room, but know when to say no. (A follow-up for a\nnon-critical issue is fine, but not a blatant break that won't add more\nlines or context.)\n\n\n## The Art Of The GIF\n\n\n>  If a Picture Speaks 1,000 Words a animated GIF Speaks 100,000.\n\n\nWhile this is the least technical aspect of the entire post it is perhaps\nthe most interesting and the easiest to implement.\n\n\nDid you know that 93% of communication is nonverbal? I didn't, until I\nstarted seeing GIFs in code reviews. When I began to see them pop up in\nreviews, they deeply caught my attention, and I began to wonder why they had\nsuch a lasting impression on me as a developer.\n\n\nWords are powerful, but images are particularly powerful because of their\nties to our emotions. Images have the potential to create powerful emotional\nresponses, and when you see something that sparks a sense of positivity, it\nsets the tone for the entire review. You **understand fully** that the\nreviewer really cares and wants to communicate that care non-verbally.\n\n\nSo how do you use GIFs in your merge requests and code reviews? Well, you\ncould [start with our handbook\ninstructions](/handbook/product/making-gifs/), but the short and sweet\nversion:\n\n\n1. Use a screen recorder to capture the video you want to show as a GIF.\n\n2. Grab yourself a copy of [gifify](https://github.com/vvo/gifify).\n\n3. GIF all day long!\n\n\n### GIFs That Show You Care\n\n\nI won't ever forget the first time I saw a [funny GIF in a code\nreview](https://gitlab.com/gitlab-org/gitlab-ui/-/merge_requests/1193#note_307290889).\nI never even made it to reading the comment, because all I could comprehend\nwas this animated GIF of a thumbs-up and I remember thinking: *This merge\nwould pass review. It would all be okay.* The sheer childlike giddy nature\nof seeing this image in action made me smile ear-to-ear. Every other comment\ncould have been a rant about how awful my code was, but I wouldn't have\ncared.\n\n\nIf I can give you one piece of advice for your code reviews as a reviewer,\nuse GIFs in a light-hearted way, because they are:\n\n\n- empathy-laden\n\n- soften the blow of a hard topic\n\n- foster positivity\n\n- make code reviews fun!\n\n\n![teamwork](https://media.giphy.com/media/vcHTRiZOglHNu/giphy.gif)\n\n\nWe're currently looking at making [Giphy a integrated feature here at\nGitLab](https://gitlab.com/gitlab-org/gitlab/-/issues/17379), making your\ncode reviews even easier and more fun!\n\n\n## Tactical code reviews through the value of iteration\n\n\n> Can we make this smaller? - Clement\nHo([@ClemMakesApps](https://gitlab.com/ClemMakesApps))\n\n\nOne thing I have noticed that help time and time again for better code\nreviews is the idea of breaking down a merge request into the smallest piece\npossible. A few people in my time here at GitLab have really put this across\nas a valuable way of working, but it was my frontend engineering manager\nClement Ho([@ClemMakesApps](https://gitlab.com/ClemMakesApps)) that I really\ntook notice championing this ideal. Given that I started paying close\nattention to this idea and began to notice benefits almost immediately when\nimplementing the idea.\n\n\nIf we look at the GitLab value handbook's [suggestions iteration\ncompetency](https://handbook.gitlab.com/handbook/values/#iteration-competency) you can see that the\nvalue in small, digestible merge requests which translates into smaller code\nreviews:\n\n\n| Level | Demonstrates Iteration Competency by… |\n\n|\n","unfiltered",[23,24,25],"code review","zero trust","GitOps",{"slug":27,"featured":6,"template":28},"better-code-reviews","BlogPost","content:en-us:blog:better-code-reviews.yml","yaml","Better Code Reviews","content","en-us/blog/better-code-reviews.yml","en-us/blog/better-code-reviews","yml",{"_path":37,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"data":39,"_id":461,"_type":30,"title":462,"_source":32,"_file":463,"_stem":464,"_extension":35},"/shared/en-us/main-navigation","en-us",{"logo":40,"freeTrial":45,"sales":50,"login":55,"items":60,"search":392,"minimal":423,"duo":442,"pricingDeployment":451},{"config":41},{"href":42,"dataGaName":43,"dataGaLocation":44},"/","gitlab logo","header",{"text":46,"config":47},"Get free trial",{"href":48,"dataGaName":49,"dataGaLocation":44},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":51,"config":52},"Talk to sales",{"href":53,"dataGaName":54,"dataGaLocation":44},"/sales/","sales",{"text":56,"config":57},"Sign in",{"href":58,"dataGaName":59,"dataGaLocation":44},"https://gitlab.com/users/sign_in/","sign in",[61,105,203,208,313,373],{"text":62,"config":63,"cards":65,"footer":88},"Platform",{"dataNavLevelOne":64},"platform",[66,72,80],{"title":62,"description":67,"link":68},"The most comprehensive AI-powered DevSecOps Platform",{"text":69,"config":70},"Explore our Platform",{"href":71,"dataGaName":64,"dataGaLocation":44},"/platform/",{"title":73,"description":74,"link":75},"GitLab Duo (AI)","Build software faster with AI at every stage of development",{"text":76,"config":77},"Meet GitLab Duo",{"href":78,"dataGaName":79,"dataGaLocation":44},"/gitlab-duo/","gitlab duo ai",{"title":81,"description":82,"link":83},"Why GitLab","10 reasons why Enterprises choose GitLab",{"text":84,"config":85},"Learn more",{"href":86,"dataGaName":87,"dataGaLocation":44},"/why-gitlab/","why gitlab",{"title":89,"items":90},"Get started with",[91,96,101],{"text":92,"config":93},"Platform Engineering",{"href":94,"dataGaName":95,"dataGaLocation":44},"/solutions/platform-engineering/","platform engineering",{"text":97,"config":98},"Developer Experience",{"href":99,"dataGaName":100,"dataGaLocation":44},"/developer-experience/","Developer experience",{"text":102,"config":103},"MLOps",{"href":104,"dataGaName":102,"dataGaLocation":44},"/topics/devops/the-role-of-ai-in-devops/",{"text":106,"left":107,"config":108,"link":110,"lists":114,"footer":185},"Product",true,{"dataNavLevelOne":109},"solutions",{"text":111,"config":112},"View all Solutions",{"href":113,"dataGaName":109,"dataGaLocation":44},"/solutions/",[115,140,164],{"title":116,"description":117,"link":118,"items":123},"Automation","CI/CD and automation to accelerate deployment",{"config":119},{"icon":120,"href":121,"dataGaName":122,"dataGaLocation":44},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[124,128,132,136],{"text":125,"config":126},"CI/CD",{"href":127,"dataGaLocation":44,"dataGaName":125},"/solutions/continuous-integration/",{"text":129,"config":130},"AI-Assisted Development",{"href":78,"dataGaLocation":44,"dataGaName":131},"AI assisted development",{"text":133,"config":134},"Source Code Management",{"href":135,"dataGaLocation":44,"dataGaName":133},"/solutions/source-code-management/",{"text":137,"config":138},"Automated Software Delivery",{"href":121,"dataGaLocation":44,"dataGaName":139},"Automated software delivery",{"title":141,"description":142,"link":143,"items":148},"Security","Deliver code faster without compromising security",{"config":144},{"href":145,"dataGaName":146,"dataGaLocation":44,"icon":147},"/solutions/security-compliance/","security and compliance","ShieldCheckLight",[149,154,159],{"text":150,"config":151},"Application Security Testing",{"href":152,"dataGaName":153,"dataGaLocation":44},"/solutions/application-security-testing/","Application security testing",{"text":155,"config":156},"Software Supply Chain Security",{"href":157,"dataGaLocation":44,"dataGaName":158},"/solutions/supply-chain/","Software supply chain security",{"text":160,"config":161},"Software Compliance",{"href":162,"dataGaName":163,"dataGaLocation":44},"/solutions/software-compliance/","software compliance",{"title":165,"link":166,"items":171},"Measurement",{"config":167},{"icon":168,"href":169,"dataGaName":170,"dataGaLocation":44},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[172,176,180],{"text":173,"config":174},"Visibility & Measurement",{"href":169,"dataGaLocation":44,"dataGaName":175},"Visibility and Measurement",{"text":177,"config":178},"Value Stream Management",{"href":179,"dataGaLocation":44,"dataGaName":177},"/solutions/value-stream-management/",{"text":181,"config":182},"Analytics & Insights",{"href":183,"dataGaLocation":44,"dataGaName":184},"/solutions/analytics-and-insights/","Analytics and insights",{"title":186,"items":187},"GitLab for",[188,193,198],{"text":189,"config":190},"Enterprise",{"href":191,"dataGaLocation":44,"dataGaName":192},"/enterprise/","enterprise",{"text":194,"config":195},"Small Business",{"href":196,"dataGaLocation":44,"dataGaName":197},"/small-business/","small business",{"text":199,"config":200},"Public Sector",{"href":201,"dataGaLocation":44,"dataGaName":202},"/solutions/public-sector/","public sector",{"text":204,"config":205},"Pricing",{"href":206,"dataGaName":207,"dataGaLocation":44,"dataNavLevelOne":207},"/pricing/","pricing",{"text":209,"config":210,"link":212,"lists":216,"feature":300},"Resources",{"dataNavLevelOne":211},"resources",{"text":213,"config":214},"View all resources",{"href":215,"dataGaName":211,"dataGaLocation":44},"/resources/",[217,250,272],{"title":218,"items":219},"Getting started",[220,225,230,235,240,245],{"text":221,"config":222},"Install",{"href":223,"dataGaName":224,"dataGaLocation":44},"/install/","install",{"text":226,"config":227},"Quick start guides",{"href":228,"dataGaName":229,"dataGaLocation":44},"/get-started/","quick setup checklists",{"text":231,"config":232},"Learn",{"href":233,"dataGaLocation":44,"dataGaName":234},"https://university.gitlab.com/","learn",{"text":236,"config":237},"Product documentation",{"href":238,"dataGaName":239,"dataGaLocation":44},"https://docs.gitlab.com/","product documentation",{"text":241,"config":242},"Best practice videos",{"href":243,"dataGaName":244,"dataGaLocation":44},"/getting-started-videos/","best practice videos",{"text":246,"config":247},"Integrations",{"href":248,"dataGaName":249,"dataGaLocation":44},"/integrations/","integrations",{"title":251,"items":252},"Discover",[253,258,262,267],{"text":254,"config":255},"Customer success stories",{"href":256,"dataGaName":257,"dataGaLocation":44},"/customers/","customer success stories",{"text":259,"config":260},"Blog",{"href":261,"dataGaName":5,"dataGaLocation":44},"/blog/",{"text":263,"config":264},"Remote",{"href":265,"dataGaName":266,"dataGaLocation":44},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"text":268,"config":269},"TeamOps",{"href":270,"dataGaName":271,"dataGaLocation":44},"/teamops/","teamops",{"title":273,"items":274},"Connect",[275,280,285,290,295],{"text":276,"config":277},"GitLab Services",{"href":278,"dataGaName":279,"dataGaLocation":44},"/services/","services",{"text":281,"config":282},"Community",{"href":283,"dataGaName":284,"dataGaLocation":44},"/community/","community",{"text":286,"config":287},"Forum",{"href":288,"dataGaName":289,"dataGaLocation":44},"https://forum.gitlab.com/","forum",{"text":291,"config":292},"Events",{"href":293,"dataGaName":294,"dataGaLocation":44},"/events/","events",{"text":296,"config":297},"Partners",{"href":298,"dataGaName":299,"dataGaLocation":44},"/partners/","partners",{"backgroundColor":301,"textColor":302,"text":303,"image":304,"link":308},"#2f2a6b","#fff","Insights for the future of software development",{"altText":305,"config":306},"the source promo card",{"src":307},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758208064/dzl0dbift9xdizyelkk4.svg",{"text":309,"config":310},"Read the latest",{"href":311,"dataGaName":312,"dataGaLocation":44},"/the-source/","the source",{"text":314,"config":315,"lists":317},"Company",{"dataNavLevelOne":316},"company",[318],{"items":319},[320,325,331,333,338,343,348,353,358,363,368],{"text":321,"config":322},"About",{"href":323,"dataGaName":324,"dataGaLocation":44},"/company/","about",{"text":326,"config":327,"footerGa":330},"Jobs",{"href":328,"dataGaName":329,"dataGaLocation":44},"/jobs/","jobs",{"dataGaName":329},{"text":291,"config":332},{"href":293,"dataGaName":294,"dataGaLocation":44},{"text":334,"config":335},"Leadership",{"href":336,"dataGaName":337,"dataGaLocation":44},"/company/team/e-group/","leadership",{"text":339,"config":340},"Team",{"href":341,"dataGaName":342,"dataGaLocation":44},"/company/team/","team",{"text":344,"config":345},"Handbook",{"href":346,"dataGaName":347,"dataGaLocation":44},"https://handbook.gitlab.com/","handbook",{"text":349,"config":350},"Investor relations",{"href":351,"dataGaName":352,"dataGaLocation":44},"https://ir.gitlab.com/","investor relations",{"text":354,"config":355},"Trust Center",{"href":356,"dataGaName":357,"dataGaLocation":44},"/security/","trust center",{"text":359,"config":360},"AI Transparency Center",{"href":361,"dataGaName":362,"dataGaLocation":44},"/ai-transparency-center/","ai transparency center",{"text":364,"config":365},"Newsletter",{"href":366,"dataGaName":367,"dataGaLocation":44},"/company/contact/","newsletter",{"text":369,"config":370},"Press",{"href":371,"dataGaName":372,"dataGaLocation":44},"/press/","press",{"text":374,"config":375,"lists":376},"Contact us",{"dataNavLevelOne":316},[377],{"items":378},[379,382,387],{"text":51,"config":380},{"href":53,"dataGaName":381,"dataGaLocation":44},"talk to sales",{"text":383,"config":384},"Get help",{"href":385,"dataGaName":386,"dataGaLocation":44},"/support/","get help",{"text":388,"config":389},"Customer portal",{"href":390,"dataGaName":391,"dataGaLocation":44},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":393,"login":394,"suggestions":401},"Close",{"text":395,"link":396},"To search repositories and projects, login to",{"text":397,"config":398},"gitlab.com",{"href":58,"dataGaName":399,"dataGaLocation":400},"search login","search",{"text":402,"default":403},"Suggestions",[404,406,410,412,416,420],{"text":73,"config":405},{"href":78,"dataGaName":73,"dataGaLocation":400},{"text":407,"config":408},"Code Suggestions (AI)",{"href":409,"dataGaName":407,"dataGaLocation":400},"/solutions/code-suggestions/",{"text":125,"config":411},{"href":127,"dataGaName":125,"dataGaLocation":400},{"text":413,"config":414},"GitLab on AWS",{"href":415,"dataGaName":413,"dataGaLocation":400},"/partners/technology-partners/aws/",{"text":417,"config":418},"GitLab on Google Cloud",{"href":419,"dataGaName":417,"dataGaLocation":400},"/partners/technology-partners/google-cloud-platform/",{"text":421,"config":422},"Why GitLab?",{"href":86,"dataGaName":421,"dataGaLocation":400},{"freeTrial":424,"mobileIcon":429,"desktopIcon":434,"secondaryButton":437},{"text":425,"config":426},"Start free trial",{"href":427,"dataGaName":49,"dataGaLocation":428},"https://gitlab.com/-/trials/new/","nav",{"altText":430,"config":431},"Gitlab Icon",{"src":432,"dataGaName":433,"dataGaLocation":428},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":430,"config":435},{"src":436,"dataGaName":433,"dataGaLocation":428},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":438,"config":439},"Get Started",{"href":440,"dataGaName":441,"dataGaLocation":428},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/compare/gitlab-vs-github/","get started",{"freeTrial":443,"mobileIcon":447,"desktopIcon":449},{"text":444,"config":445},"Learn more about GitLab Duo",{"href":78,"dataGaName":446,"dataGaLocation":428},"gitlab duo",{"altText":430,"config":448},{"src":432,"dataGaName":433,"dataGaLocation":428},{"altText":430,"config":450},{"src":436,"dataGaName":433,"dataGaLocation":428},{"freeTrial":452,"mobileIcon":457,"desktopIcon":459},{"text":453,"config":454},"Back to pricing",{"href":206,"dataGaName":455,"dataGaLocation":428,"icon":456},"back to pricing","GoBack",{"altText":430,"config":458},{"src":432,"dataGaName":433,"dataGaLocation":428},{"altText":430,"config":460},{"src":436,"dataGaName":433,"dataGaLocation":428},"content:shared:en-us:main-navigation.yml","Main Navigation","shared/en-us/main-navigation.yml","shared/en-us/main-navigation",{"_path":466,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"title":467,"button":468,"image":473,"config":477,"_id":479,"_type":30,"_source":32,"_file":480,"_stem":481,"_extension":35},"/shared/en-us/banner","is now in public beta!",{"text":469,"config":470},"Try the Beta",{"href":471,"dataGaName":472,"dataGaLocation":44},"/gitlab-duo/agent-platform/","duo banner",{"altText":474,"config":475},"GitLab Duo Agent Platform",{"src":476},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1753720689/somrf9zaunk0xlt7ne4x.svg",{"layout":478},"release","content:shared:en-us:banner.yml","shared/en-us/banner.yml","shared/en-us/banner",{"_path":483,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"data":484,"_id":687,"_type":30,"title":688,"_source":32,"_file":689,"_stem":690,"_extension":35},"/shared/en-us/main-footer",{"text":485,"source":486,"edit":492,"contribute":497,"config":502,"items":507,"minimal":679},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":487,"config":488},"View page source",{"href":489,"dataGaName":490,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":493,"config":494},"Edit this page",{"href":495,"dataGaName":496,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":498,"config":499},"Please contribute",{"href":500,"dataGaName":501,"dataGaLocation":491},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":503,"facebook":504,"youtube":505,"linkedin":506},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[508,531,586,615,649],{"title":62,"links":509,"subMenu":514},[510],{"text":511,"config":512},"DevSecOps platform",{"href":71,"dataGaName":513,"dataGaLocation":491},"devsecops platform",[515],{"title":204,"links":516},[517,521,526],{"text":518,"config":519},"View plans",{"href":206,"dataGaName":520,"dataGaLocation":491},"view plans",{"text":522,"config":523},"Why Premium?",{"href":524,"dataGaName":525,"dataGaLocation":491},"/pricing/premium/","why premium",{"text":527,"config":528},"Why Ultimate?",{"href":529,"dataGaName":530,"dataGaLocation":491},"/pricing/ultimate/","why ultimate",{"title":532,"links":533},"Solutions",[534,539,541,543,548,553,557,560,564,568,570,573,576,581],{"text":535,"config":536},"Digital transformation",{"href":537,"dataGaName":538,"dataGaLocation":491},"/topics/digital-transformation/","digital transformation",{"text":150,"config":540},{"href":152,"dataGaName":150,"dataGaLocation":491},{"text":139,"config":542},{"href":121,"dataGaName":122,"dataGaLocation":491},{"text":544,"config":545},"Agile development",{"href":546,"dataGaName":547,"dataGaLocation":491},"/solutions/agile-delivery/","agile delivery",{"text":549,"config":550},"Cloud transformation",{"href":551,"dataGaName":552,"dataGaLocation":491},"/topics/cloud-native/","cloud transformation",{"text":554,"config":555},"SCM",{"href":135,"dataGaName":556,"dataGaLocation":491},"source code management",{"text":125,"config":558},{"href":127,"dataGaName":559,"dataGaLocation":491},"continuous integration & delivery",{"text":561,"config":562},"Value stream management",{"href":179,"dataGaName":563,"dataGaLocation":491},"value stream management",{"text":25,"config":565},{"href":566,"dataGaName":567,"dataGaLocation":491},"/solutions/gitops/","gitops",{"text":189,"config":569},{"href":191,"dataGaName":192,"dataGaLocation":491},{"text":571,"config":572},"Small business",{"href":196,"dataGaName":197,"dataGaLocation":491},{"text":574,"config":575},"Public sector",{"href":201,"dataGaName":202,"dataGaLocation":491},{"text":577,"config":578},"Education",{"href":579,"dataGaName":580,"dataGaLocation":491},"/solutions/education/","education",{"text":582,"config":583},"Financial services",{"href":584,"dataGaName":585,"dataGaLocation":491},"/solutions/finance/","financial services",{"title":209,"links":587},[588,590,592,594,597,599,601,603,605,607,609,611,613],{"text":221,"config":589},{"href":223,"dataGaName":224,"dataGaLocation":491},{"text":226,"config":591},{"href":228,"dataGaName":229,"dataGaLocation":491},{"text":231,"config":593},{"href":233,"dataGaName":234,"dataGaLocation":491},{"text":236,"config":595},{"href":238,"dataGaName":596,"dataGaLocation":491},"docs",{"text":259,"config":598},{"href":261,"dataGaName":5,"dataGaLocation":491},{"text":254,"config":600},{"href":256,"dataGaName":257,"dataGaLocation":491},{"text":263,"config":602},{"href":265,"dataGaName":266,"dataGaLocation":491},{"text":276,"config":604},{"href":278,"dataGaName":279,"dataGaLocation":491},{"text":268,"config":606},{"href":270,"dataGaName":271,"dataGaLocation":491},{"text":281,"config":608},{"href":283,"dataGaName":284,"dataGaLocation":491},{"text":286,"config":610},{"href":288,"dataGaName":289,"dataGaLocation":491},{"text":291,"config":612},{"href":293,"dataGaName":294,"dataGaLocation":491},{"text":296,"config":614},{"href":298,"dataGaName":299,"dataGaLocation":491},{"title":314,"links":616},[617,619,621,623,625,627,629,633,638,640,642,644],{"text":321,"config":618},{"href":323,"dataGaName":316,"dataGaLocation":491},{"text":326,"config":620},{"href":328,"dataGaName":329,"dataGaLocation":491},{"text":334,"config":622},{"href":336,"dataGaName":337,"dataGaLocation":491},{"text":339,"config":624},{"href":341,"dataGaName":342,"dataGaLocation":491},{"text":344,"config":626},{"href":346,"dataGaName":347,"dataGaLocation":491},{"text":349,"config":628},{"href":351,"dataGaName":352,"dataGaLocation":491},{"text":630,"config":631},"Sustainability",{"href":632,"dataGaName":630,"dataGaLocation":491},"/sustainability/",{"text":634,"config":635},"Diversity, inclusion and belonging (DIB)",{"href":636,"dataGaName":637,"dataGaLocation":491},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":354,"config":639},{"href":356,"dataGaName":357,"dataGaLocation":491},{"text":364,"config":641},{"href":366,"dataGaName":367,"dataGaLocation":491},{"text":369,"config":643},{"href":371,"dataGaName":372,"dataGaLocation":491},{"text":645,"config":646},"Modern Slavery Transparency Statement",{"href":647,"dataGaName":648,"dataGaLocation":491},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"title":650,"links":651},"Contact Us",[652,655,657,659,664,669,674],{"text":653,"config":654},"Contact an expert",{"href":53,"dataGaName":54,"dataGaLocation":491},{"text":383,"config":656},{"href":385,"dataGaName":386,"dataGaLocation":491},{"text":388,"config":658},{"href":390,"dataGaName":391,"dataGaLocation":491},{"text":660,"config":661},"Status",{"href":662,"dataGaName":663,"dataGaLocation":491},"https://status.gitlab.com/","status",{"text":665,"config":666},"Terms of use",{"href":667,"dataGaName":668,"dataGaLocation":491},"/terms/","terms of use",{"text":670,"config":671},"Privacy statement",{"href":672,"dataGaName":673,"dataGaLocation":491},"/privacy/","privacy statement",{"text":675,"config":676},"Cookie preferences",{"dataGaName":677,"dataGaLocation":491,"id":678,"isOneTrustButton":107},"cookie preferences","ot-sdk-btn",{"items":680},[681,683,685],{"text":665,"config":682},{"href":667,"dataGaName":668,"dataGaLocation":491},{"text":670,"config":684},{"href":672,"dataGaName":673,"dataGaLocation":491},{"text":675,"config":686},{"dataGaName":677,"dataGaLocation":491,"id":678,"isOneTrustButton":107},"content:shared:en-us:main-footer.yml","Main Footer","shared/en-us/main-footer.yml","shared/en-us/main-footer",[692],{"_path":693,"_dir":694,"_draft":6,"_partial":6,"_locale":7,"content":695,"config":699,"_id":701,"_type":30,"title":702,"_source":32,"_file":703,"_stem":704,"_extension":35},"/en-us/blog/authors/david-oregan","authors",{"name":18,"config":696},{"headshot":697,"ctfId":698},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749659853/Blog/Author%20Headshots/oregand-headshot.png","oregand",{"template":700},"BlogAuthor","content:en-us:blog:authors:david-oregan.yml","David Oregan","en-us/blog/authors/david-oregan.yml","en-us/blog/authors/david-oregan",{"_path":706,"_dir":38,"_draft":6,"_partial":6,"_locale":7,"header":707,"eyebrow":708,"blurb":709,"button":710,"secondaryButton":714,"_id":716,"_type":30,"title":717,"_source":32,"_file":718,"_stem":719,"_extension":35},"/shared/en-us/next-steps","Start shipping better software faster","50%+ of the Fortune 100 trust GitLab","See what your team can do with the intelligent\n\n\nDevSecOps platform.\n",{"text":46,"config":711},{"href":712,"dataGaName":49,"dataGaLocation":713},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":51,"config":715},{"href":53,"dataGaName":54,"dataGaLocation":713},"content:shared:en-us:next-steps.yml","Next Steps","shared/en-us/next-steps.yml","shared/en-us/next-steps",1758326215824]