[{"data":1,"prerenderedAt":2062},["ShallowReactive",2],{"/blog/journey-through-gits-20-year-history":3,"navigation-en-us":1276,"banner-en-us":1704,"footer-en-us":1714,"blog-post-authors-en-us-Patrick Steinhardt":1959,"blog-related-posts-en-us-journey-through-gits-20-year-history":1974,"blog-promotions-en-us":1998,"next-steps-en-us":2052},{"id":4,"title":5,"authors":6,"body":8,"category":1257,"date":1258,"description":1259,"extension":1260,"externalUrl":1261,"faq":1261,"featured":622,"heroImage":1262,"meta":1263,"navigation":622,"path":1264,"seo":1265,"slug":1270,"stem":1271,"tags":1272,"template":1274,"updatedDate":1261,"__hash__":1275},"blogPosts/en-us/blog/journey-through-gits-20-year-history.md","Journey through Git's 20-year history",[7],"Patrick Steinhardt",{"type":9,"value":10,"toc":1237},"minimark",[11,15,18,23,31,34,207,210,250,257,260,329,340,343,349,354,361,384,387,509,512,632,638,642,649,770,776,779,799,803,806,809,828,834,842,854,858,861,870,873,877,880,887,891,894,910,917,1003,1006,1016,1020,1027,1034,1043,1049,1058,1064,1067,1073,1077,1080,1087,1092,1095,1109,1112,1115,1121,1137,1141,1144,1147,1158,1173,1176,1180,1183,1186,1191,1194,1199,1202,1206,1233],[12,13,14],"p",{},"The Git project has just turned 20 years old. A lot has happened during these years, and while the conceptual design of Git hasn't changed significantly since its inception, the way users interact with the tool has changed quite significantly. We at GitLab are proud to build on top of this critical piece of software and to be part of its history.",[12,16,17],{},"Join us on a journey through Git's history to explore how it has evolved over the years.",[19,20,22],"h2",{"id":21},"the-first-commit","The first commit",[12,24,25,26,30],{},"The first commit was made on April 7, 2005, by Linus Torvalds, the creator of the Linux kernel: ",[27,28,29],"code",{},"e83c5163316 (Initial revision of \"git\", the information manager from hell, 2005-04-07)",".",[12,32,33],{},"As we can see, this\ncommit does not contain a lot of files:",[35,36,41],"pre",{"className":37,"code":38,"language":39,"meta":40,"style":40},"language-shell shiki shiki-themes github-light","$ git ls-tree e83c5163316\n100644 blob a6bba79ba1f46a1bbf7773449c3bd2bb9bf48e8b    Makefile\n100644 blob 27577f76849c09d3405397244eb3d8ae1d11b0f3    README\n100644 blob 98a32a9ad39883c6d05a000a68511d4b1ee2b3c7    cache.h\n100644 blob 74a0a234dd346fff51c773aa57d82fc4b83a8557    cat-file.c\n100644 blob 840307af0cfaab31555795ce7175d5e9c9f981a0    commit-tree.c\n100644 blob 25dc13fe101b219f74007f3194b787dd99e863da    init-db.c\n100644 blob c924a6e0fc4c36bad6f23cb87ee59518c771f936    read-cache.c\n100644 blob 1b47742d8cbc0d98903777758b7b519980e7499e    read-tree.c\n100644 blob b8522886a15db861508fb6d03d4d88d6de912a4b    show-diff.c\n100644 blob 5085a5cb53ee52e1886ff6d46c609bdb2fc6d6cd    update-cache.c\n100644 blob 921f981353229db0c56103a52609d35aff16f41b    write-tree.c\n","shell","",[27,42,43,62,77,90,103,116,129,142,155,168,181,194],{"__ignoreMap":40},[44,45,48,52,56,59],"span",{"class":46,"line":47},"line",1,[44,49,51],{"class":50},"s7eDp","$",[44,53,55],{"class":54},"sYBdl"," git",[44,57,58],{"class":54}," ls-tree",[44,60,61],{"class":54}," e83c5163316\n",[44,63,65,68,71,74],{"class":46,"line":64},2,[44,66,67],{"class":50},"100644",[44,69,70],{"class":54}," blob",[44,72,73],{"class":54}," a6bba79ba1f46a1bbf7773449c3bd2bb9bf48e8b",[44,75,76],{"class":54},"    Makefile\n",[44,78,80,82,84,87],{"class":46,"line":79},3,[44,81,67],{"class":50},[44,83,70],{"class":54},[44,85,86],{"class":54}," 27577f76849c09d3405397244eb3d8ae1d11b0f3",[44,88,89],{"class":54},"    README\n",[44,91,93,95,97,100],{"class":46,"line":92},4,[44,94,67],{"class":50},[44,96,70],{"class":54},[44,98,99],{"class":54}," 98a32a9ad39883c6d05a000a68511d4b1ee2b3c7",[44,101,102],{"class":54},"    cache.h\n",[44,104,106,108,110,113],{"class":46,"line":105},5,[44,107,67],{"class":50},[44,109,70],{"class":54},[44,111,112],{"class":54}," 74a0a234dd346fff51c773aa57d82fc4b83a8557",[44,114,115],{"class":54},"    cat-file.c\n",[44,117,119,121,123,126],{"class":46,"line":118},6,[44,120,67],{"class":50},[44,122,70],{"class":54},[44,124,125],{"class":54}," 840307af0cfaab31555795ce7175d5e9c9f981a0",[44,127,128],{"class":54},"    commit-tree.c\n",[44,130,132,134,136,139],{"class":46,"line":131},7,[44,133,67],{"class":50},[44,135,70],{"class":54},[44,137,138],{"class":54}," 25dc13fe101b219f74007f3194b787dd99e863da",[44,140,141],{"class":54},"    init-db.c\n",[44,143,145,147,149,152],{"class":46,"line":144},8,[44,146,67],{"class":50},[44,148,70],{"class":54},[44,150,151],{"class":54}," c924a6e0fc4c36bad6f23cb87ee59518c771f936",[44,153,154],{"class":54},"    read-cache.c\n",[44,156,158,160,162,165],{"class":46,"line":157},9,[44,159,67],{"class":50},[44,161,70],{"class":54},[44,163,164],{"class":54}," 1b47742d8cbc0d98903777758b7b519980e7499e",[44,166,167],{"class":54},"    read-tree.c\n",[44,169,171,173,175,178],{"class":46,"line":170},10,[44,172,67],{"class":50},[44,174,70],{"class":54},[44,176,177],{"class":54}," b8522886a15db861508fb6d03d4d88d6de912a4b",[44,179,180],{"class":54},"    show-diff.c\n",[44,182,184,186,188,191],{"class":46,"line":183},11,[44,185,67],{"class":50},[44,187,70],{"class":54},[44,189,190],{"class":54}," 5085a5cb53ee52e1886ff6d46c609bdb2fc6d6cd",[44,192,193],{"class":54},"    update-cache.c\n",[44,195,197,199,201,204],{"class":46,"line":196},12,[44,198,67],{"class":50},[44,200,70],{"class":54},[44,202,203],{"class":54}," 921f981353229db0c56103a52609d35aff16f41b",[44,205,206],{"class":54},"    write-tree.c\n",[12,208,209],{},"In addition to build infrastructure, the first commit provides seven top-level commands:",[211,212,213,220,226,232,238,244],"ul",{},[214,215,216,219],"li",{},[27,217,218],{},"init-db"," to initialize a new Git repository",[214,221,222,225],{},[27,223,224],{},"update-cache"," to add files to the index",[214,227,228,231],{},[27,229,230],{},"write-tree"," to take what is in the index and create a new tree from it",[214,233,234,237],{},[27,235,236],{},"read-tree"," to read a tree object",[214,239,240,243],{},[27,241,242],{},"commit-tree"," to create a commit from a tree",[214,245,246,249],{},[27,247,248],{},"cat-file"," to read a specific object into a temporary file",[12,251,252,253,256],{},"Note that the ",[27,254,255],{},"git"," command itself did not yet exist at this point in time.\nInstead, these commands had to be executed directly.",[12,258,259],{},"As example, let's create a\nnew repository:",[35,261,263],{"className":37,"code":262,"language":39,"meta":40,"style":40},"$ mkdir repo\n$ cd repo\n$ init-db\ndefaulting to private storage area\n$ ls -a\n.  ..  .dircache\n",[27,264,265,275,284,291,308,319],{"__ignoreMap":40},[44,266,267,269,272],{"class":46,"line":47},[44,268,51],{"class":50},[44,270,271],{"class":54}," mkdir",[44,273,274],{"class":54}," repo\n",[44,276,277,279,282],{"class":46,"line":64},[44,278,51],{"class":50},[44,280,281],{"class":54}," cd",[44,283,274],{"class":54},[44,285,286,288],{"class":46,"line":79},[44,287,51],{"class":50},[44,289,290],{"class":54}," init-db\n",[44,292,293,296,299,302,305],{"class":46,"line":92},[44,294,295],{"class":50},"defaulting",[44,297,298],{"class":54}," to",[44,300,301],{"class":54}," private",[44,303,304],{"class":54}," storage",[44,306,307],{"class":54}," area\n",[44,309,310,312,315],{"class":46,"line":105},[44,311,51],{"class":50},[44,313,314],{"class":54}," ls",[44,316,318],{"class":317},"sYu0t"," -a\n",[44,320,321,323,326],{"class":46,"line":118},[44,322,30],{"class":317},[44,324,325],{"class":54},"  ..",[44,327,328],{"class":54},"  .dircache\n",[12,330,331,332,335,336,339],{},"That looks quite unfamiliar: There is no ",[27,333,334],{},".git"," directory, but there is a\n",[27,337,338],{},".dircache"," directory. And where was the private storage area?",[12,341,342],{},"The early design of Git distinguished between a \"shared\" and \"private\" object\nstorage area. This object storage area was where all of your Git objects went. For example, your\ncommits and blobs.",[12,344,345,346,348],{},"By default, ",[27,347,218],{}," created a private object storage area that was only used for\nthe managed directory that it was created in. A \"shared\" object storage area, on\nthe other hand, shared object content across multiple managed directories so\nthat the same object did not need to be stored twice.",[350,351,353],"h3",{"id":352},"create-a-commit","Create a commit",[12,355,356,357,360],{},"So, now that we have a repository, how did we create a commit? Well, it isn't as\neasy as today's ",[27,358,359],{},"git add . && git commit",". Instead, you had to:",[362,363,364,370,376,379],"ol",{},[214,365,366,367,369],{},"Update the index by calling ",[27,368,224],{}," for every file that you want to\nadd.",[214,371,372,373,375],{},"Write a new tree by calling ",[27,374,230],{},", which takes everything you have\nadded to the index.",[214,377,378],{},"Set up environment variables to tell Git who you are.",[214,380,381,382,30],{},"Write a commit object by calling ",[27,383,242],{},[12,385,386],{},"Let’s create a commit in the repository:",[35,388,390],{"className":37,"code":389,"language":39,"meta":40,"style":40},"$ echo content-1 >file-a\n$ update-cache file-a\n$ echo content-2 >file-b\n$ update-cache file-b\n$ write-tree\n3f143dfb48f2d84936626e2e5402e1f10c2050fb\n$ export COMMITTER_NAME=\"Patrick Steinhardt\"\n$ export COMMITER_EMAIL=ps@pks.im\n$ echo \"commit message\" | commit-tree 3f143dfb48f2d84936626e2e5402e1f10c2050fb\nCommitting initial tree 3f143dfb48f2d84936626e2e5402e1f10c2050fb\n5f8e928066c03cebe5fd0a0cc1b93d058155b969\n",[27,391,392,409,419,433,442,449,454,464,473,491,504],{"__ignoreMap":40},[44,393,394,396,399,402,406],{"class":46,"line":47},[44,395,51],{"class":50},[44,397,398],{"class":54}," echo",[44,400,401],{"class":54}," content-1",[44,403,405],{"class":404},"sD7c4"," >",[44,407,408],{"class":54},"file-a\n",[44,410,411,413,416],{"class":46,"line":64},[44,412,51],{"class":50},[44,414,415],{"class":54}," update-cache",[44,417,418],{"class":54}," file-a\n",[44,420,421,423,425,428,430],{"class":46,"line":79},[44,422,51],{"class":50},[44,424,398],{"class":54},[44,426,427],{"class":54}," content-2",[44,429,405],{"class":404},[44,431,432],{"class":54},"file-b\n",[44,434,435,437,439],{"class":46,"line":92},[44,436,51],{"class":50},[44,438,415],{"class":54},[44,440,441],{"class":54}," file-b\n",[44,443,444,446],{"class":46,"line":105},[44,445,51],{"class":50},[44,447,448],{"class":54}," write-tree\n",[44,450,451],{"class":46,"line":118},[44,452,453],{"class":50},"3f143dfb48f2d84936626e2e5402e1f10c2050fb\n",[44,455,456,458,461],{"class":46,"line":131},[44,457,51],{"class":50},[44,459,460],{"class":54}," export",[44,462,463],{"class":54}," COMMITTER_NAME=\"Patrick Steinhardt\"\n",[44,465,466,468,470],{"class":46,"line":144},[44,467,51],{"class":50},[44,469,460],{"class":54},[44,471,472],{"class":54}," COMMITER_EMAIL=ps@pks.im\n",[44,474,475,477,479,482,485,488],{"class":46,"line":157},[44,476,51],{"class":50},[44,478,398],{"class":54},[44,480,481],{"class":54}," \"commit message\"",[44,483,484],{"class":404}," |",[44,486,487],{"class":50}," commit-tree",[44,489,490],{"class":54}," 3f143dfb48f2d84936626e2e5402e1f10c2050fb\n",[44,492,493,496,499,502],{"class":46,"line":170},[44,494,495],{"class":50},"Committing",[44,497,498],{"class":54}," initial",[44,500,501],{"class":54}," tree",[44,503,490],{"class":54},[44,505,506],{"class":46,"line":183},[44,507,508],{"class":50},"5f8e928066c03cebe5fd0a0cc1b93d058155b969\n",[12,510,511],{},"This isn't exactly ergonomic, but it works! Let's have a look at the generated\ncommit:",[35,513,515],{"className":37,"code":514,"language":39,"meta":40,"style":40},"$ cat-file 5f8e928066c03cebe5fd0a0cc1b93d058155b969\ntemp_git_file_rlTXtE: commit\n$ cat temp_git_file_rlTXtE\ntree 3f143dfb48f2d84936626e2e5402e1f10c2050fb\nauthor Patrick Steinhardt \u003Cps@pks.im> Wed Mar 26 13:10:16 2025\ncommitter Patrick Steinhardt \u003Cps@pks.im> Wed Mar 26 13:10:16 2025\n\ncommit message\n",[27,516,517,527,535,545,552,591,618,624],{"__ignoreMap":40},[44,518,519,521,524],{"class":46,"line":47},[44,520,51],{"class":50},[44,522,523],{"class":54}," cat-file",[44,525,526],{"class":54}," 5f8e928066c03cebe5fd0a0cc1b93d058155b969\n",[44,528,529,532],{"class":46,"line":64},[44,530,531],{"class":50},"temp_git_file_rlTXtE:",[44,533,534],{"class":54}," commit\n",[44,536,537,539,542],{"class":46,"line":79},[44,538,51],{"class":50},[44,540,541],{"class":54}," cat",[44,543,544],{"class":54}," temp_git_file_rlTXtE\n",[44,546,547,550],{"class":46,"line":92},[44,548,549],{"class":50},"tree",[44,551,490],{"class":54},[44,553,554,557,560,563,566,569,573,576,579,582,585,588],{"class":46,"line":105},[44,555,556],{"class":50},"author",[44,558,559],{"class":54}," Patrick",[44,561,562],{"class":54}," Steinhardt",[44,564,565],{"class":404}," \u003C",[44,567,568],{"class":54},"ps@pks.i",[44,570,572],{"class":571},"sgsFI","m",[44,574,575],{"class":404},">",[44,577,578],{"class":54}," Wed",[44,580,581],{"class":54}," Mar",[44,583,584],{"class":317}," 26",[44,586,587],{"class":54}," 13:10:16",[44,589,590],{"class":317}," 2025\n",[44,592,593,596,598,600,602,604,606,608,610,612,614,616],{"class":46,"line":118},[44,594,595],{"class":50},"committer",[44,597,559],{"class":54},[44,599,562],{"class":54},[44,601,565],{"class":404},[44,603,568],{"class":54},[44,605,572],{"class":571},[44,607,575],{"class":404},[44,609,578],{"class":54},[44,611,581],{"class":54},[44,613,584],{"class":317},[44,615,587],{"class":54},[44,617,590],{"class":317},[44,619,620],{"class":46,"line":131},[44,621,623],{"emptyLinePlaceholder":622},true,"\n",[44,625,626,629],{"class":46,"line":144},[44,627,628],{"class":50},"commit",[44,630,631],{"class":54}," message\n",[12,633,634,635,637],{},"Note that ",[27,636,248],{}," didn't print the contents directly, but instead wrote\nit into a temporary file first. But the contents of the file looked exactly how a\nmodern commit would look.",[350,639,641],{"id":640},"making-changes","Making changes",[12,643,644,645,648],{},"Now that we have files, how do we get their status? You might have guessed it:\nthis could be done with ",[27,646,647],{},"show-diff",":",[35,650,652],{"className":37,"code":651,"language":39,"meta":40,"style":40},"$ show-diff\nfile-a: ok\nfile-b: ok\n\n$ echo modified-content >file-a\n$ show-diff\n--- -   2025-03-26 13:14:53.457611094 +0100\n+++ file-a  2025-03-26 13:14:52.230085756 +0100\n@@ -1 +1 @@\n-content-1\n+modified-content\nfile-a:  46d8be14cdec97aac6a769fdbce4db340e888bf8\nfile-b: ok\n",[27,653,654,661,669,676,680,693,699,716,732,746,751,756,763],{"__ignoreMap":40},[44,655,656,658],{"class":46,"line":47},[44,657,51],{"class":50},[44,659,660],{"class":54}," show-diff\n",[44,662,663,666],{"class":46,"line":64},[44,664,665],{"class":50},"file-a:",[44,667,668],{"class":54}," ok\n",[44,670,671,674],{"class":46,"line":79},[44,672,673],{"class":50},"file-b:",[44,675,668],{"class":54},[44,677,678],{"class":46,"line":92},[44,679,623],{"emptyLinePlaceholder":622},[44,681,682,684,686,689,691],{"class":46,"line":105},[44,683,51],{"class":50},[44,685,398],{"class":54},[44,687,688],{"class":54}," modified-content",[44,690,405],{"class":404},[44,692,408],{"class":54},[44,694,695,697],{"class":46,"line":118},[44,696,51],{"class":50},[44,698,660],{"class":54},[44,700,701,704,707,710,713],{"class":46,"line":131},[44,702,703],{"class":50},"---",[44,705,706],{"class":54}," -",[44,708,709],{"class":54},"   2025-03-26",[44,711,712],{"class":54}," 13:14:53.457611094",[44,714,715],{"class":54}," +0100\n",[44,717,718,721,724,727,730],{"class":46,"line":144},[44,719,720],{"class":50},"+++",[44,722,723],{"class":54}," file-a",[44,725,726],{"class":54},"  2025-03-26",[44,728,729],{"class":54}," 13:14:52.230085756",[44,731,715],{"class":54},[44,733,734,737,740,743],{"class":46,"line":157},[44,735,736],{"class":50},"@@",[44,738,739],{"class":317}," -1",[44,741,742],{"class":54}," +1",[44,744,745],{"class":54}," @@\n",[44,747,748],{"class":46,"line":170},[44,749,750],{"class":50},"-content-1\n",[44,752,753],{"class":46,"line":183},[44,754,755],{"class":50},"+modified-content\n",[44,757,758,760],{"class":46,"line":196},[44,759,665],{"class":50},[44,761,762],{"class":54},"  46d8be14cdec97aac6a769fdbce4db340e888bf8\n",[44,764,766,768],{"class":46,"line":765},13,[44,767,673],{"class":50},[44,769,668],{"class":54},[12,771,772,773,775],{},"Amazingly, ",[27,774,647],{}," even knew to already generate diffs between the old and\nnew state of modified files! Funny enough though, Git achieved this by simply\nexecuting the diff(1) Unix tool.",[12,777,778],{},"In summary, all of this was still rather bare-bones, but it performed all of the\nnecessary duties to track history. There were still many limitations:",[211,780,781,784,787,790,796],{},[214,782,783],{},"There was no easy way yet to switch between commits.",[214,785,786],{},"There was no way to show logs.",[214,788,789],{},"There were no branches, tags, or even references. Users were expected to manually\nkeep track of object IDs.",[214,791,792,793,795],{},"There was no way to synchronize two repositories with one another. Instead,\nusers were expected to use rsync(1) to synchronize the ",[27,794,338],{}," directories.",[214,797,798],{},"There was no way to perform merges.",[19,800,802],{"id":801},"git-099","Git 0.99",[12,804,805],{},"The first test release of Git was Version 0.99. This release came only two months after\nthe initial commit, but already contained 1,076 commits. There had been almost 50\ndifferent developers involved. The most frequent committer at this point was\nLinus himself, but he was closely followed by Junio Hamano, the current maintainer.",[12,807,808],{},"A lot of things had changed since the initial commit:",[211,810,811,814,817,825],{},[214,812,813],{},"Git started to track different development branches by using references, which\nin most cases removes the need to manually track object IDs.",[214,815,816],{},"There was a new remote protocol that allows two repositories to exchange\nobjects with one another.",[214,818,819,820,822,823,30],{},"The ",[27,821,338],{}," directory was renamed to ",[27,824,334],{},[214,826,827],{},"It became possible to merge single files with one another.",[12,829,830,831,833],{},"The most important visible change, though, was the introduction of\nthe top-level ",[27,832,255],{}," command and its subcommands. Interestingly, this release\nalso created the notion of \"plumbing\" and \"porcelain\" commands:",[211,835,836,839],{},[214,837,838],{},"\"Plumbing\" tools are the low-level commands that access the underlying Git\nrepository.",[214,840,841],{},"\"Porcelain\" tools are shell scripts that wrap the plumbing commands to provide\na nicer, high-level user interface.",[12,843,844,845,853],{},"This split still exists nowadays as documented in\n",[846,847,850],"a",{"href":848,"rel":849},"https://git-scm.com/docs/git#_high_level_commands_porcelain",[],[27,851,852],{},"git(1)",", but because most porcelain tools have been rewritten from shell scripts to C, the line between these two\ncategories has started to blur significantly.",[19,855,857],{"id":856},"linus-hands-over-maintainership","Linus hands over maintainership",[12,859,860],{},"Linus never started Git out of love for version control systems, but because there was a need to replace BitKeeper for Linux kernel development. As such, he never planned to keep maintaining Git forever. The intent was to maintain it until someone trustworthy stepped up.",[12,862,863,864,869],{},"That someone was Junio Hamano. Junio got involved in Git about a week after Linus’s first commit and already had a couple of hundred commits in the history after the Git 0.99 release. So, on July 26, 2005, ",[846,865,868],{"href":866,"rel":867},"https://lore.kernel.org/git/Pine.LNX.4.58.0507262004320.3227@g5.osdl.org/",[],"Linus made Junio the new maintainer of the Git project",". While Linus has continued to contribute to Git, his involvement with the project faded over time, which is only natural considering that he is quite busy as head of the Linux project.",[12,871,872],{},"Junio is still leading the Git project today.",[19,874,876],{"id":875},"git-10","Git 1.0",[12,878,879],{},"The first major release of Git happened on December 21, 2005, by\nJunio. Interestingly enough, there had been 34 releases between Version 0.99\nand Version 1.0: 0.99.1 to 0.99.7, 0.99.7a to 0.99.7d, 0.99.8 to 0.99.8g, and\n0.99.9 up to 0.99.9n.",[12,881,882,883,886],{},"One of the more important milestones since 0.99 was probably the addition of the ",[27,884,885],{},"git-merge(1)","\ncommand that allows one to merge two trees with one another. This is in stark\ncontrast to before, where one had to basically script the merges file by file.",[350,888,890],{"id":889},"remotes","Remotes",[12,892,893],{},"Another significant change was the introduction of shorthand notation for\nremote repositories. While Git already knew how to talk to remote repositories,\nusers always had to specify the URL to fetch from every single time they wanted\nto fetch changes from it. This was quite unfriendly to the users, because, typically, they wanted to interact with the same remote over and over again.",[12,895,896,897,900,901,904,905,909],{},"You may know about how remotes work now, but the mechanism that existed at  this point in time was still significantly different. There was no ",[27,898,899],{},"git-remote(1)","  command that you could use to manage your remotes. Remotes weren't even stored  in your ",[27,902,903],{},".git/config"," file. In fact, when remotes were first introduced in  Version 0.99.2, Git didn't even ",[906,907,908],"em",{},"have"," config files.",[12,911,912,913,916],{},"Instead, you had to configure remotes by writing a file into the  ",[27,914,915],{},".git/branches"," directory, which nowadays feels somewhat counterintuitive. But  the mechanism still works today:",[35,918,920],{"className":37,"code":919,"language":39,"meta":40,"style":40},"$ git init repo --\nInitialized empty Git repository in /tmp/repo/.git/\n$ cd repo\n$ mkdir .git/branches\n$ echo https://gitlab.com/git-scm/git.git >.git/branches/origin\n$ git fetch origin refs/heads/master\n",[27,921,922,937,957,965,974,988],{"__ignoreMap":40},[44,923,924,926,928,931,934],{"class":46,"line":47},[44,925,51],{"class":50},[44,927,55],{"class":54},[44,929,930],{"class":54}," init",[44,932,933],{"class":54}," repo",[44,935,936],{"class":317}," --\n",[44,938,939,942,945,948,951,954],{"class":46,"line":64},[44,940,941],{"class":50},"Initialized",[44,943,944],{"class":54}," empty",[44,946,947],{"class":54}," Git",[44,949,950],{"class":54}," repository",[44,952,953],{"class":54}," in",[44,955,956],{"class":54}," /tmp/repo/.git/\n",[44,958,959,961,963],{"class":46,"line":79},[44,960,51],{"class":50},[44,962,281],{"class":54},[44,964,274],{"class":54},[44,966,967,969,971],{"class":46,"line":92},[44,968,51],{"class":50},[44,970,271],{"class":54},[44,972,973],{"class":54}," .git/branches\n",[44,975,976,978,980,983,985],{"class":46,"line":105},[44,977,51],{"class":50},[44,979,398],{"class":54},[44,981,982],{"class":54}," https://gitlab.com/git-scm/git.git",[44,984,405],{"class":404},[44,986,987],{"class":54},".git/branches/origin\n",[44,989,990,992,994,997,1000],{"class":46,"line":118},[44,991,51],{"class":50},[44,993,55],{"class":54},[44,995,996],{"class":54}," fetch",[44,998,999],{"class":54}," origin",[44,1001,1002],{"class":54}," refs/heads/master\n",[12,1004,1005],{},"But that isn't all! The directory was soon renamed in Git Version 0.99.5 to \"remotes\", so there are a total of three different ways to configure remotes in a modern Git client.",[12,1007,1008,1009,1011,1012,1015],{},"Most of you have probably never used either ",[27,1010,915],{}," nor ",[27,1013,1014],{},".git/remotes",",  and both of these mechanisms have been deprecated since 2005 and 2011,  respectively. Furthermore, these directories will finally be removed in Git 3.0.",[19,1017,1019],{"id":1018},"git-branding","Git branding",[12,1021,1022,1023,1026],{},"In 2007, the first Git logo was created. It’s arguable if you can call it a logo, because it only consisted of three red minus signs above three green plus signs, reflecting what the output of ",[27,1024,1025],{},"git diff"," looks like:",[12,1028,1029],{},[1030,1031],"img",{"alt":1032,"src":1033},"three red minus signs above three green plus signs, reflecting what the output of git diff","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097388/Blog/Content%20Images/Blog/Content%20Images/image3_aHR0cHM6_1750097387927.png",[12,1035,1036,1037,1042],{},"A bit later, in 2008, the website ",[846,1038,1041],{"href":1039,"rel":1040},"https://git-scm.com",[],"git-scm.com"," was launched:",[12,1044,1045],{},[1030,1046],{"alt":1047,"src":1048},"landing page for git-scm.com in 2006","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097388/Blog/Content%20Images/Blog/Content%20Images/image4_aHR0cHM6_1750097387930.png",[12,1050,1051,1052,1057],{},"In 2012, the Git website was ",[846,1053,1056],{"href":1054,"rel":1055},"https://lore.kernel.org/git/CAP2yMaJy=1c3b4F72h6jL_454+0ydEQNXYiC6E-ZeQQgE0PcVA@mail.gmail.com/",[],"revamped"," by Scott Chacon and Jason Long. It looks pretty similar to how it looks today:",[12,1059,1060],{},[1030,1061],{"alt":1062,"src":1063},"git website revamped in 2012","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097388/Blog/Content%20Images/Blog/Content%20Images/image2_aHR0cHM6_1750097387932.png",[12,1065,1066],{},"This site redesign sports the new red-orange logo designed by Jason Long; the same logo that's currently used:",[12,1068,1069],{},[1030,1070],{"alt":1071,"src":1072},"git logo","https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097388/Blog/Content%20Images/Blog/Content%20Images/image1_aHR0cHM6_1750097387934.png",[19,1074,1076],{"id":1075},"git-20","Git 2.0",[12,1078,1079],{},"Git already started to look a lot like modern Git at the 1.0 release, so we\nare going to do a big historical jump to Git 2.0. This version was\nreleased around 10 years after Git 1.0 and was the first release that\nintentionally contained backwards-incompatible changes in central workflows.",[350,1081,1083,1086],{"id":1082},"git-push1-default-behavior",[27,1084,1085],{},"git-push(1)"," default behavior",[12,1088,1089,1090,30],{},"The change that arguably caused most the confusion in this release was the\nupdated default behavior of ",[27,1091,1085],{},[12,1093,1094],{},"There are a couple of different actions that Git could take when you push\ninto a remote repository and don’t specify exactly what you want to push:",[211,1096,1097,1100,1103,1106],{},[214,1098,1099],{},"Git could refuse to do anything, asking you to provide more information of\nwhat exactly you want to push.",[214,1101,1102],{},"Git could push the currently checked out branch.",[214,1104,1105],{},"Git could push the currently checked out branch, but only if it knows that it\nhas an equivalent on the remote side.",[214,1107,1108],{},"Git could push all of your branches that have an equivalent on the remote side.",[12,1110,1111],{},"The behavior of modern Git is the so-called \"simple\" strategy, which is the third\noption above. But before Git 2.0, the default behavior was the \"matching\"\nstrategy, which is the last option.",[12,1113,1114],{},"The “matching” strategy was significantly more risky. You always had to make sure that you\nwere fine with pushing all of your local branches that have an equivalent on the\nremote side before pushing. Otherwise, you might have ended up\npushing changes unintentionally. As such, it was decided to change the strategy\nto \"simple\" to reduce the risk and help out Git beginners.",[350,1116,1118],{"id":1117},"git-add1",[27,1119,1120],{},"git-add(1)",[12,1122,1123,1124,1126,1127,1129,1130,1133,1134,1136],{},"Another big change was the default behavior of ",[27,1125,1120],{}," when it comes to  tracked files that have been deleted. Before Git 2.0, ",[27,1128,1120],{}," wouldn't  stage deleted files automatically, but you instead had to manually add each  deleted file by using ",[27,1131,1132],{},"git-rm(1)"," to make them part of a commit. With Git 2.0, this behavior was changed so that ",[27,1135,1120],{}," also adds deleted files to the index.",[19,1138,1140],{"id":1139},"celebrating-the-git-community","Celebrating the Git community",[12,1142,1143],{},"I won’t bore you with the details around how Git works nowadays – you probably use it daily anyway, and, if you don’t, there are many tutorials out there that can help you get started. Instead, let’s celebrate the Git community, which has ensured that Git works as well as it does 20 years later.",[12,1145,1146],{},"Over time, Git has:",[211,1148,1149,1152,1155],{},[214,1150,1151],{},"Accumulated 56,721 commits as of the Git 2.49 release.",[214,1153,1154],{},"Received contributions from more than 2,000 different individuals.",[214,1156,1157],{},"Published 60 major releases.",[12,1159,1160,1161,1166,1167,1172],{},"The Git project also has a steady influx of new contributors by taking part in ",[846,1162,1165],{"href":1163,"rel":1164},"https://summerofcode.withgoogle.com/",[],"Google Summer of Code"," and ",[846,1168,1171],{"href":1169,"rel":1170},"https://www.outreachy.org/",[],"Outreachy",". New contributors like these are what will ensure that the Git project will remain healthy in the long term.",[12,1174,1175],{},"As such, let me extend a big thank you to all contributors. It is your contributions that have made Git possible.",[19,1177,1179],{"id":1178},"going-forward","Going forward",[12,1181,1182],{},"It should be an uncontroversial take to say that Git has essentially won the competition of version control systems. It has significant market share, and it isn't easy to find open source projects that are using a version control system other than Git. So it has clearly done a lot of things right.",[12,1184,1185],{},"That being said, its development hasn't stood still, and there are still many challenges ahead of Git. On the one hand, we have technical challenges:",[211,1187,1188],{},[214,1189,1190],{},"modernization of an aging code base  - scaling with the ever-growing size of monorepos  - handling large binary files better",[12,1192,1193],{},"And on the other hand, there are problems of a more social type:",[211,1195,1196],{},[214,1197,1198],{},"improving the usability of Git  - fostering the Git community so that the project remains healthy in the long    term",[12,1200,1201],{},"There always remains work to be done and we at GitLab are proud to be part  of these efforts to make sure that Git continues to be a great version control  system for the next 20 years.",[19,1203,1205],{"id":1204},"read-more-about-git","Read more about Git",[211,1207,1208,1215],{},[214,1209,1210],{},[846,1211,1214],{"href":1212,"rel":1213},"https://about.gitlab.com/blog/celebrating-gits-20th-anniversary-with-creator-linus-torvalds/",[],"Celebrating Git's 20th anniversary with creator Linus Torvalds",[214,1216,1217,1222,1223,1222,1228],{},[846,1218,1221],{"href":1219,"rel":1220},"https://about.gitlab.com/blog/whats-new-in-git-2-49-0/",[],"What's new in Git 2.49.0?","  - ",[846,1224,1227],{"href":1225,"rel":1226},"https://about.gitlab.com/blog/whats-new-in-git-2-48-0/",[],"What’s new in Git 2.48.0?",[846,1229,1232],{"href":1230,"rel":1231},"https://about.gitlab.com/blog/a-beginners-guide-to-the-git-reftable-format/",[],"A beginner's guide to the Git reftable format",[1234,1235,1236],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}",{"title":40,"searchDepth":64,"depth":64,"links":1238},[1239,1243,1244,1245,1248,1249,1254,1255,1256],{"id":21,"depth":64,"text":22,"children":1240},[1241,1242],{"id":352,"depth":79,"text":353},{"id":640,"depth":79,"text":641},{"id":801,"depth":64,"text":802},{"id":856,"depth":64,"text":857},{"id":875,"depth":64,"text":876,"children":1246},[1247],{"id":889,"depth":79,"text":890},{"id":1018,"depth":64,"text":1019},{"id":1075,"depth":64,"text":1076,"children":1250},[1251,1253],{"id":1082,"depth":79,"text":1252},"git-push(1) default behavior",{"id":1117,"depth":79,"text":1120},{"id":1139,"depth":64,"text":1140},{"id":1178,"depth":64,"text":1179},{"id":1204,"depth":64,"text":1205},"open-source","2025-04-14","Follow along as we reminisce about the first commit, the unique aspects of the earliest releases, and the confusion sparked by an update to the git-push(1) default behavior.","md",null,"https://res.cloudinary.com/about-gitlab-com/image/upload/v1750097380/Blog/Hero%20Images/Blog/Hero%20Images/git-20-years-opt2_TWNsNk8KH43b3jP0KLD0U_1750097380123.png",{},"/en-us/blog/journey-through-gits-20-year-history",{"title":5,"description":1259,"ogTitle":5,"ogDescription":1259,"noIndex":1266,"ogImage":1262,"ogUrl":1267,"ogSiteName":1268,"ogType":1269,"canonicalUrls":1267},false,"https://about.gitlab.com/blog/journey-through-gits-20-year-history","https://about.gitlab.com","article","journey-through-gits-20-year-history","en-us/blog/journey-through-gits-20-year-history",[1273,255],"open source","BlogPost","35DeOOmV6qm9wI795M1ACzP2UeDEBrQHtLCtNJ63d0U",{"logo":1277,"freeTrial":1282,"sales":1287,"login":1292,"items":1297,"search":1624,"minimal":1655,"duo":1674,"switchNav":1683,"pricingDeployment":1694},{"config":1278},{"href":1279,"dataGaName":1280,"dataGaLocation":1281},"/","gitlab logo","header",{"text":1283,"config":1284},"Get free trial",{"href":1285,"dataGaName":1286,"dataGaLocation":1281},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com&glm_content=default-saas-trial/","free trial",{"text":1288,"config":1289},"Request a demo",{"href":1290,"dataGaName":1291,"dataGaLocation":1281},"/sales/?contact-topic=request-demo","sales",{"text":1293,"config":1294},"Sign in",{"href":1295,"dataGaName":1296,"dataGaLocation":1281},"https://gitlab.com/users/sign_in/","sign in",[1298,1327,1427,1432,1546,1602],{"text":1299,"config":1300,"menu":1302},"Platform",{"dataNavLevelOne":1301},"platform",{"type":1303,"columns":1304},"cards",[1305,1311,1319],{"title":1299,"description":1306,"link":1307},"The intelligent orchestration platform for DevSecOps",{"text":1308,"config":1309},"Explore our Platform",{"href":1310,"dataGaName":1301,"dataGaLocation":1281},"/platform/",{"title":1312,"description":1313,"link":1314},"GitLab Duo Agent Platform","Agentic AI for the entire software lifecycle",{"text":1315,"config":1316},"Meet GitLab Duo",{"href":1317,"dataGaName":1318,"dataGaLocation":1281},"/gitlab-duo-agent-platform/","gitlab duo agent platform",{"title":1320,"description":1321,"link":1322},"Why GitLab","See the top reasons enterprises choose GitLab",{"text":1323,"config":1324},"Learn more",{"href":1325,"dataGaName":1326,"dataGaLocation":1281},"/why-gitlab/","why gitlab",{"text":1328,"left":622,"config":1329,"menu":1331},"Product",{"dataNavLevelOne":1330},"solutions",{"type":1332,"link":1333,"columns":1337,"feature":1406},"lists",{"text":1334,"config":1335},"View all Solutions",{"href":1336,"dataGaName":1330,"dataGaLocation":1281},"/solutions/",[1338,1362,1385],{"title":1339,"description":1340,"link":1341,"items":1346},"Automation","CI/CD and automation to accelerate deployment",{"config":1342},{"icon":1343,"href":1344,"dataGaName":1345,"dataGaLocation":1281},"AutomatedCodeAlt","/solutions/delivery-automation/","automated software delivery",[1347,1351,1354,1358],{"text":1348,"config":1349},"CI/CD",{"href":1350,"dataGaLocation":1281,"dataGaName":1348},"/solutions/continuous-integration/",{"text":1312,"config":1352},{"href":1317,"dataGaLocation":1281,"dataGaName":1353},"gitlab duo agent platform - product menu",{"text":1355,"config":1356},"Source Code Management",{"href":1357,"dataGaLocation":1281,"dataGaName":1355},"/solutions/source-code-management/",{"text":1359,"config":1360},"Automated Software Delivery",{"href":1344,"dataGaLocation":1281,"dataGaName":1361},"Automated software delivery",{"title":1363,"description":1364,"link":1365,"items":1370},"Security","Deliver code faster without compromising security",{"config":1366},{"href":1367,"dataGaName":1368,"dataGaLocation":1281,"icon":1369},"/solutions/application-security-testing/","security and compliance","ShieldCheckLight",[1371,1375,1380],{"text":1372,"config":1373},"Application Security Testing",{"href":1367,"dataGaName":1374,"dataGaLocation":1281},"Application security testing",{"text":1376,"config":1377},"Software Supply Chain Security",{"href":1378,"dataGaLocation":1281,"dataGaName":1379},"/solutions/supply-chain/","Software supply chain security",{"text":1381,"config":1382},"Software Compliance",{"href":1383,"dataGaName":1384,"dataGaLocation":1281},"/solutions/software-compliance/","software compliance",{"title":1386,"link":1387,"items":1392},"Measurement",{"config":1388},{"icon":1389,"href":1390,"dataGaName":1391,"dataGaLocation":1281},"DigitalTransformation","/solutions/visibility-measurement/","visibility and measurement",[1393,1397,1401],{"text":1394,"config":1395},"Visibility & Measurement",{"href":1390,"dataGaLocation":1281,"dataGaName":1396},"Visibility and Measurement",{"text":1398,"config":1399},"Value Stream Management",{"href":1400,"dataGaLocation":1281,"dataGaName":1398},"/solutions/value-stream-management/",{"text":1402,"config":1403},"Analytics & Insights",{"href":1404,"dataGaLocation":1281,"dataGaName":1405},"/solutions/analytics-and-insights/","Analytics and insights",{"title":1407,"type":1332,"items":1408},"GitLab for",[1409,1415,1421],{"text":1410,"config":1411},"Enterprise",{"icon":1412,"href":1413,"dataGaLocation":1281,"dataGaName":1414},"Building","/enterprise/","enterprise",{"text":1416,"config":1417},"Small Business",{"icon":1418,"href":1419,"dataGaLocation":1281,"dataGaName":1420},"Work","/small-business/","small business",{"text":1422,"config":1423},"Public Sector",{"icon":1424,"href":1425,"dataGaLocation":1281,"dataGaName":1426},"Organization","/solutions/public-sector/","public sector",{"text":1428,"config":1429},"Pricing",{"href":1430,"dataGaName":1431,"dataGaLocation":1281,"dataNavLevelOne":1431},"/pricing/","pricing",{"text":1433,"config":1434,"menu":1436},"Resources",{"dataNavLevelOne":1435},"resources",{"type":1332,"link":1437,"columns":1441,"feature":1535},{"text":1438,"config":1439},"View all resources",{"href":1440,"dataGaName":1435,"dataGaLocation":1281},"/resources/",[1442,1475,1502],{"title":1443,"items":1444},"Getting started",[1445,1450,1455,1460,1465,1470],{"text":1446,"config":1447},"Install",{"href":1448,"dataGaName":1449,"dataGaLocation":1281},"/install/","install",{"text":1451,"config":1452},"Quick start guides",{"href":1453,"dataGaName":1454,"dataGaLocation":1281},"/get-started/","quick setup checklists",{"text":1456,"config":1457},"Learn",{"href":1458,"dataGaLocation":1281,"dataGaName":1459},"https://university.gitlab.com/","learn",{"text":1461,"config":1462},"Product documentation",{"href":1463,"dataGaName":1464,"dataGaLocation":1281},"https://docs.gitlab.com/","product documentation",{"text":1466,"config":1467},"Best practice videos",{"href":1468,"dataGaName":1469,"dataGaLocation":1281},"/getting-started-videos/","best practice videos",{"text":1471,"config":1472},"Integrations",{"href":1473,"dataGaName":1474,"dataGaLocation":1281},"/integrations/","integrations",{"title":1476,"items":1477},"Discover",[1478,1483,1488,1493,1497],{"text":1479,"config":1480},"Customer success stories",{"href":1481,"dataGaName":1482,"dataGaLocation":1281},"/customers/","customer success stories",{"text":1484,"config":1485},"Blog",{"href":1486,"dataGaName":1487,"dataGaLocation":1281},"/blog/","blog",{"text":1489,"config":1490},"Demo Hub",{"href":1491,"dataGaName":1492,"dataGaLocation":1281},"/demo-hub/","demo hub",{"text":1494,"config":1495},"The Source",{"href":1496,"dataGaName":1487,"dataGaLocation":1281},"/the-source/",{"text":1498,"config":1499},"Remote",{"href":1500,"dataGaName":1501,"dataGaLocation":1281},"https://handbook.gitlab.com/handbook/company/culture/all-remote/","remote",{"title":1503,"items":1504},"Connect",[1505,1510,1515,1520,1525,1530],{"text":1506,"config":1507},"GitLab Services",{"href":1508,"dataGaName":1509,"dataGaLocation":1281},"/services/","services",{"text":1511,"config":1512},"Contribute",{"href":1513,"dataGaName":1514,"dataGaLocation":1281},"https://contributors.gitlab.com","contribute",{"text":1516,"config":1517},"Community",{"href":1518,"dataGaName":1519,"dataGaLocation":1281},"/community/","community",{"text":1521,"config":1522},"Forum",{"href":1523,"dataGaName":1524,"dataGaLocation":1281},"https://forum.gitlab.com/","forum",{"text":1526,"config":1527},"Events",{"href":1528,"dataGaName":1529,"dataGaLocation":1281},"/events/","events",{"text":1531,"config":1532},"Partners",{"href":1533,"dataGaName":1534,"dataGaLocation":1281},"/partners/","partners",{"config":1536,"title":1539,"text":1540,"link":1541},{"background":1537,"textColor":1538},"url('https://res.cloudinary.com/about-gitlab-com/image/upload/v1777322348/qpq8yrgn8knii57omj0c.png')","#000","What’s new in GitLab","Stay updated with our latest features and improvements.",{"text":1542,"config":1543},"Read the latest",{"href":1544,"dataGaName":1545,"dataGaLocation":1281},"/whats-new/","whats new",{"text":1547,"config":1548,"menu":1550},"Company",{"dataNavLevelOne":1549},"company",{"type":1332,"columns":1551},[1552],{"items":1553},[1554,1559,1565,1567,1572,1577,1582,1587,1592,1597],{"text":1555,"config":1556},"About",{"href":1557,"dataGaName":1558,"dataGaLocation":1281},"/company/","about",{"text":1560,"config":1561,"footerGa":1564},"Jobs",{"href":1562,"dataGaName":1563,"dataGaLocation":1281},"/jobs/","jobs",{"dataGaName":1563},{"text":1526,"config":1566},{"href":1528,"dataGaName":1529,"dataGaLocation":1281},{"text":1568,"config":1569},"Leadership",{"href":1570,"dataGaName":1571,"dataGaLocation":1281},"/company/team/e-group/","leadership",{"text":1573,"config":1574},"Handbook",{"href":1575,"dataGaName":1576,"dataGaLocation":1281},"https://handbook.gitlab.com/","handbook",{"text":1578,"config":1579},"Investor relations",{"href":1580,"dataGaName":1581,"dataGaLocation":1281},"https://ir.gitlab.com/overview/default.aspx","investor relations",{"text":1583,"config":1584},"Trust Center",{"href":1585,"dataGaName":1586,"dataGaLocation":1281},"/security/","trust center",{"text":1588,"config":1589},"AI Transparency Center",{"href":1590,"dataGaName":1591,"dataGaLocation":1281},"/ai-transparency-center/","ai transparency center",{"text":1593,"config":1594},"Newsletter",{"href":1595,"dataGaName":1596,"dataGaLocation":1281},"/company/contact/#contact-forms","newsletter",{"text":1598,"config":1599},"Press",{"href":1600,"dataGaName":1601,"dataGaLocation":1281},"/press/","press",{"text":1603,"config":1604,"menu":1605},"Contact us",{"dataNavLevelOne":1549},{"type":1332,"columns":1606},[1607],{"items":1608},[1609,1614,1619],{"text":1610,"config":1611},"Talk to sales",{"href":1612,"dataGaName":1613,"dataGaLocation":1281},"/sales/","talk to sales",{"text":1615,"config":1616},"Support portal",{"href":1617,"dataGaName":1618,"dataGaLocation":1281},"https://support.gitlab.com/hc/en-us","support portal",{"text":1620,"config":1621},"Customer portal",{"href":1622,"dataGaName":1623,"dataGaLocation":1281},"https://customers.gitlab.com/customers/sign_in/","customer portal",{"close":1625,"login":1626,"suggestions":1633},"Close",{"text":1627,"link":1628},"To search repositories and projects, login to",{"text":1629,"config":1630},"gitlab.com",{"href":1295,"dataGaName":1631,"dataGaLocation":1632},"search login","search",{"text":1634,"default":1635},"Suggestions",[1636,1638,1642,1644,1648,1652],{"text":1312,"config":1637},{"href":1317,"dataGaName":1312,"dataGaLocation":1632},{"text":1639,"config":1640},"Code Suggestions (AI)",{"href":1641,"dataGaName":1639,"dataGaLocation":1632},"/solutions/code-suggestions/",{"text":1348,"config":1643},{"href":1350,"dataGaName":1348,"dataGaLocation":1632},{"text":1645,"config":1646},"GitLab on AWS",{"href":1647,"dataGaName":1645,"dataGaLocation":1632},"/partners/technology-partners/aws/",{"text":1649,"config":1650},"GitLab on Google Cloud",{"href":1651,"dataGaName":1649,"dataGaLocation":1632},"/partners/technology-partners/google-cloud-platform/",{"text":1653,"config":1654},"Why GitLab?",{"href":1325,"dataGaName":1653,"dataGaLocation":1632},{"freeTrial":1656,"mobileIcon":1661,"desktopIcon":1666,"secondaryButton":1669},{"text":1657,"config":1658},"Start free trial",{"href":1659,"dataGaName":1286,"dataGaLocation":1660},"https://gitlab.com/-/trials/new/","nav",{"altText":1662,"config":1663},"Gitlab Icon",{"src":1664,"dataGaName":1665,"dataGaLocation":1660},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203874/jypbw1jx72aexsoohd7x.svg","gitlab icon",{"altText":1662,"config":1667},{"src":1668,"dataGaName":1665,"dataGaLocation":1660},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1758203875/gs4c8p8opsgvflgkswz9.svg",{"text":1670,"config":1671},"Get Started",{"href":1672,"dataGaName":1673,"dataGaLocation":1660},"https://gitlab.com/-/trial_registrations/new?glm_source=about.gitlab.com/get-started/","get started",{"freeTrial":1675,"mobileIcon":1679,"desktopIcon":1681},{"text":1676,"config":1677},"Learn more about GitLab Duo",{"href":1317,"dataGaName":1678,"dataGaLocation":1660},"gitlab duo",{"altText":1662,"config":1680},{"src":1664,"dataGaName":1665,"dataGaLocation":1660},{"altText":1662,"config":1682},{"src":1668,"dataGaName":1665,"dataGaLocation":1660},{"button":1684,"mobileIcon":1689,"desktopIcon":1691},{"text":1685,"config":1686},"/switch",{"href":1687,"dataGaName":1688,"dataGaLocation":1660},"#contact","switch",{"altText":1662,"config":1690},{"src":1664,"dataGaName":1665,"dataGaLocation":1660},{"altText":1662,"config":1692},{"src":1693,"dataGaName":1665,"dataGaLocation":1660},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1773335277/ohhpiuoxoldryzrnhfrh.png",{"freeTrial":1695,"mobileIcon":1700,"desktopIcon":1702},{"text":1696,"config":1697},"Back to pricing",{"href":1430,"dataGaName":1698,"dataGaLocation":1660,"icon":1699},"back to pricing","GoBack",{"altText":1662,"config":1701},{"src":1664,"dataGaName":1665,"dataGaLocation":1660},{"altText":1662,"config":1703},{"src":1668,"dataGaName":1665,"dataGaLocation":1660},{"title":1705,"titleMobile":1706,"button":1707,"config":1712},"Duo Agent Platform delivers 400% ROI, per new Forrester Consulting study.","400% ROI: Forrester TEI for GitLab Duo",{"text":1323,"config":1708},{"href":1709,"dataGaName":1710,"dataGaLocation":1711},"https://about.gitlab.com/blog/gitlab-duo-agent-platform-delivers-400-percent-roi/","forrester-tei-dap-banner","global-banner",{"layout":1713,"disabled":1266},"release",{"data":1715},{"text":1716,"source":1717,"edit":1723,"contribute":1728,"config":1733,"items":1738,"minimal":1948},"Git is a trademark of Software Freedom Conservancy and our use of 'GitLab' is under license",{"text":1718,"config":1719},"View page source",{"href":1720,"dataGaName":1721,"dataGaLocation":1722},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/","page source","footer",{"text":1724,"config":1725},"Edit this page",{"href":1726,"dataGaName":1727,"dataGaLocation":1722},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/content/","web ide",{"text":1729,"config":1730},"Please contribute",{"href":1731,"dataGaName":1732,"dataGaLocation":1722},"https://gitlab.com/gitlab-com/marketing/digital-experience/about-gitlab-com/-/blob/main/CONTRIBUTING.md/","please contribute",{"twitter":1734,"facebook":1735,"youtube":1736,"linkedin":1737},"https://twitter.com/gitlab","https://www.facebook.com/gitlab","https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg","https://www.linkedin.com/company/gitlab-com",[1739,1786,1840,1884,1916],{"title":1428,"links":1740,"subMenu":1755},[1741,1745,1750],{"text":1742,"config":1743},"View plans",{"href":1430,"dataGaName":1744,"dataGaLocation":1722},"view plans",{"text":1746,"config":1747},"Why Premium?",{"href":1748,"dataGaName":1749,"dataGaLocation":1722},"/pricing/premium/","why premium",{"text":1751,"config":1752},"Why Ultimate?",{"href":1753,"dataGaName":1754,"dataGaLocation":1722},"/pricing/ultimate/","why ultimate",[1756],{"title":1757,"links":1758},"Contact Us",[1759,1762,1764,1766,1771,1776,1781],{"text":1760,"config":1761},"Contact sales",{"href":1612,"dataGaName":1291,"dataGaLocation":1722},{"text":1615,"config":1763},{"href":1617,"dataGaName":1618,"dataGaLocation":1722},{"text":1620,"config":1765},{"href":1622,"dataGaName":1623,"dataGaLocation":1722},{"text":1767,"config":1768},"Status",{"href":1769,"dataGaName":1770,"dataGaLocation":1722},"https://status.gitlab.com/","status",{"text":1772,"config":1773},"Terms of use",{"href":1774,"dataGaName":1775,"dataGaLocation":1722},"/terms/","terms of use",{"text":1777,"config":1778},"Privacy statement",{"href":1779,"dataGaName":1780,"dataGaLocation":1722},"/privacy/","privacy statement",{"text":1782,"config":1783},"Cookie preferences",{"dataGaName":1784,"dataGaLocation":1722,"id":1785,"isOneTrustButton":622},"cookie preferences","ot-sdk-btn",{"title":1328,"links":1787,"subMenu":1796},[1788,1792],{"text":1789,"config":1790},"DevSecOps platform",{"href":1310,"dataGaName":1791,"dataGaLocation":1722},"devsecops platform",{"text":1793,"config":1794},"AI-Assisted Development",{"href":1317,"dataGaName":1795,"dataGaLocation":1722},"ai-assisted development",[1797],{"title":1798,"links":1799},"Topics",[1800,1805,1810,1815,1820,1825,1830,1835],{"text":1801,"config":1802},"CICD",{"href":1803,"dataGaName":1804,"dataGaLocation":1722},"/topics/ci-cd/","cicd",{"text":1806,"config":1807},"GitOps",{"href":1808,"dataGaName":1809,"dataGaLocation":1722},"/topics/gitops/","gitops",{"text":1811,"config":1812},"DevOps",{"href":1813,"dataGaName":1814,"dataGaLocation":1722},"/topics/devops/","devops",{"text":1816,"config":1817},"Version Control",{"href":1818,"dataGaName":1819,"dataGaLocation":1722},"/topics/version-control/","version control",{"text":1821,"config":1822},"DevSecOps",{"href":1823,"dataGaName":1824,"dataGaLocation":1722},"/topics/devsecops/","devsecops",{"text":1826,"config":1827},"Cloud Native",{"href":1828,"dataGaName":1829,"dataGaLocation":1722},"/topics/cloud-native/","cloud native",{"text":1831,"config":1832},"AI for Coding",{"href":1833,"dataGaName":1834,"dataGaLocation":1722},"/topics/devops/ai-for-coding/","ai for coding",{"text":1836,"config":1837},"Agentic AI",{"href":1838,"dataGaName":1839,"dataGaLocation":1722},"/topics/agentic-ai/","agentic ai",{"title":1841,"links":1842},"Solutions",[1843,1845,1847,1852,1856,1859,1863,1866,1868,1871,1874,1879],{"text":1372,"config":1844},{"href":1367,"dataGaName":1372,"dataGaLocation":1722},{"text":1361,"config":1846},{"href":1344,"dataGaName":1345,"dataGaLocation":1722},{"text":1848,"config":1849},"Agile development",{"href":1850,"dataGaName":1851,"dataGaLocation":1722},"/solutions/agile-delivery/","agile delivery",{"text":1853,"config":1854},"SCM",{"href":1357,"dataGaName":1855,"dataGaLocation":1722},"source code management",{"text":1801,"config":1857},{"href":1350,"dataGaName":1858,"dataGaLocation":1722},"continuous integration & delivery",{"text":1860,"config":1861},"Value stream management",{"href":1400,"dataGaName":1862,"dataGaLocation":1722},"value stream management",{"text":1806,"config":1864},{"href":1865,"dataGaName":1809,"dataGaLocation":1722},"/solutions/gitops/",{"text":1410,"config":1867},{"href":1413,"dataGaName":1414,"dataGaLocation":1722},{"text":1869,"config":1870},"Small business",{"href":1419,"dataGaName":1420,"dataGaLocation":1722},{"text":1872,"config":1873},"Public sector",{"href":1425,"dataGaName":1426,"dataGaLocation":1722},{"text":1875,"config":1876},"Education",{"href":1877,"dataGaName":1878,"dataGaLocation":1722},"/solutions/education/","education",{"text":1880,"config":1881},"Financial services",{"href":1882,"dataGaName":1883,"dataGaLocation":1722},"/solutions/finance/","financial services",{"title":1433,"links":1885},[1886,1888,1890,1892,1895,1897,1900,1902,1904,1906,1908,1910,1912,1914],{"text":1446,"config":1887},{"href":1448,"dataGaName":1449,"dataGaLocation":1722},{"text":1451,"config":1889},{"href":1453,"dataGaName":1454,"dataGaLocation":1722},{"text":1456,"config":1891},{"href":1458,"dataGaName":1459,"dataGaLocation":1722},{"text":1461,"config":1893},{"href":1463,"dataGaName":1894,"dataGaLocation":1722},"docs",{"text":1484,"config":1896},{"href":1486,"dataGaName":1487,"dataGaLocation":1722},{"text":1898,"config":1899},"What's new",{"href":1544,"dataGaName":1545,"dataGaLocation":1722},{"text":1479,"config":1901},{"href":1481,"dataGaName":1482,"dataGaLocation":1722},{"text":1498,"config":1903},{"href":1500,"dataGaName":1501,"dataGaLocation":1722},{"text":1506,"config":1905},{"href":1508,"dataGaName":1509,"dataGaLocation":1722},{"text":1511,"config":1907},{"href":1513,"dataGaName":1514,"dataGaLocation":1722},{"text":1516,"config":1909},{"href":1518,"dataGaName":1519,"dataGaLocation":1722},{"text":1521,"config":1911},{"href":1523,"dataGaName":1524,"dataGaLocation":1722},{"text":1526,"config":1913},{"href":1528,"dataGaName":1529,"dataGaLocation":1722},{"text":1531,"config":1915},{"href":1533,"dataGaName":1534,"dataGaLocation":1722},{"title":1547,"links":1917},[1918,1920,1922,1924,1926,1928,1932,1937,1939,1941,1943],{"text":1555,"config":1919},{"href":1557,"dataGaName":1549,"dataGaLocation":1722},{"text":1560,"config":1921},{"href":1562,"dataGaName":1563,"dataGaLocation":1722},{"text":1568,"config":1923},{"href":1570,"dataGaName":1571,"dataGaLocation":1722},{"text":1573,"config":1925},{"href":1575,"dataGaName":1576,"dataGaLocation":1722},{"text":1578,"config":1927},{"href":1580,"dataGaName":1581,"dataGaLocation":1722},{"text":1929,"config":1930},"Sustainability",{"href":1931,"dataGaName":1929,"dataGaLocation":1722},"/sustainability/",{"text":1933,"config":1934},"Diversity, inclusion and belonging (DIB)",{"href":1935,"dataGaName":1936,"dataGaLocation":1722},"/diversity-inclusion-belonging/","Diversity, inclusion and belonging",{"text":1583,"config":1938},{"href":1585,"dataGaName":1586,"dataGaLocation":1722},{"text":1593,"config":1940},{"href":1595,"dataGaName":1596,"dataGaLocation":1722},{"text":1598,"config":1942},{"href":1600,"dataGaName":1601,"dataGaLocation":1722},{"text":1944,"config":1945},"Modern Slavery Transparency Statement",{"href":1946,"dataGaName":1947,"dataGaLocation":1722},"https://handbook.gitlab.com/handbook/legal/modern-slavery-act-transparency-statement/","modern slavery transparency statement",{"items":1949},[1950,1953,1956],{"text":1951,"config":1952},"Terms",{"href":1774,"dataGaName":1775,"dataGaLocation":1722},{"text":1954,"config":1955},"Cookies",{"dataGaName":1784,"dataGaLocation":1722,"id":1785,"isOneTrustButton":622},{"text":1957,"config":1958},"Privacy",{"href":1779,"dataGaName":1780,"dataGaLocation":1722},[1960],{"id":1961,"title":7,"body":1261,"config":1962,"content":1964,"description":1261,"extension":1968,"meta":1969,"navigation":622,"path":1970,"seo":1971,"stem":1972,"__hash__":1973},"blogAuthors/en-us/blog/authors/patrick-steinhardt.yml",{"template":1963},"BlogAuthor",{"name":7,"config":1965},{"headshot":1966,"ctfId":1967},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1749661952/Blog/Author%20Headshots/pks-gitlab-headshot.png","pksgitlab","yml",{},"/en-us/blog/authors/patrick-steinhardt",{},"en-us/blog/authors/patrick-steinhardt","SV9Yd_vW69UbvntDP-SEOV9NKT_VwUAj5nfftf2ElSw",[1975,1983,1991],{"title":1976,"description":1977,"heroImage":1978,"category":1257,"date":1979,"authors":1980,"slug":1982,"externalUrl":1261},"What's new in Git 2.55.0?","Learn about the new features and changes in Git 2.55, including a new git-history(1) fixup command, an fsmonitor daemon for Linux, pushing to remote groups, and more.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782732487/ztwgrvlolpifo01vj8qc.png","2026-06-29",[1981],"Toon Claes","whats-new-in-git-2-55-0",{"title":1984,"description":1985,"heroImage":1986,"category":1257,"date":1987,"authors":1988,"slug":1990,"externalUrl":1261},"GitLab AI Hackathon 2026: Meet the winners","Nearly 7,000 developers built 600+ AI agents and flows on GitLab Duo Agent Platform. Find out who won and what they created.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1776457632/llddiylsgwuze0u1rjks.png","2026-04-22",[1989],"Nick Veenhof","gitlab-ai-hackathon-2026-meet-the-winners",{"title":1992,"description":1993,"heroImage":1994,"category":1257,"date":1995,"authors":1996,"slug":1997,"externalUrl":1261},"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.","https://res.cloudinary.com/about-gitlab-com/image/upload/v1782734716/ztwgrvlolpifo01vj8qc.png","2026-04-20",[7],"whats-new-in-git-2-54-0",{"promotions":1999},[2000,2014,2026,2038],{"id":2001,"categories":2002,"header":2004,"text":2005,"button":2006,"image":2011},"ai-modernization",[2003],"ai","Is AI achieving its promise at scale?","Quiz will take 5 minutes or less",{"text":2007,"config":2008},"Get your AI maturity score",{"href":2009,"dataGaName":2010,"dataGaLocation":1487},"/assessments/ai-modernization-assessment/","modernization assessment",{"config":2012},{"src":2013},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/qix0m7kwnd8x2fh1zq49.png",{"id":2015,"categories":2016,"header":2018,"text":2005,"button":2019,"image":2023},"devops-modernization",[2017,1824],"product","Are you just managing tools or shipping innovation?",{"text":2020,"config":2021},"Get your DevOps maturity score",{"href":2022,"dataGaName":2010,"dataGaLocation":1487},"/assessments/devops-modernization-assessment/",{"config":2024},{"src":2025},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138785/eg818fmakweyuznttgid.png",{"id":2027,"categories":2028,"header":2030,"text":2005,"button":2031,"image":2035},"security-modernization",[2029],"security","Are you trading speed for security?",{"text":2032,"config":2033},"Get your security maturity score",{"href":2034,"dataGaName":2010,"dataGaLocation":1487},"/assessments/security-modernization-assessment/",{"config":2036},{"src":2037},"https://res.cloudinary.com/about-gitlab-com/image/upload/v1772138786/p4pbqd9nnjejg5ds6mdk.png",{"id":2039,"paths":2040,"header":2043,"text":2044,"button":2045,"image":2050},"github-azure-migration",[2041,2042],"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":2046,"config":2047},"See how GitLab compares to GitHub",{"href":2048,"dataGaName":2049,"dataGaLocation":1487},"/compare/gitlab-vs-github/github-azure-migration/","github azure migration",{"config":2051},{"src":2025},{"header":2053,"blurb":2054,"button":2055,"secondaryButton":2060},"Start building faster today","See what your team can do with the intelligent orchestration platform for DevSecOps.\n",{"text":2056,"config":2057},"Get your free trial",{"href":2058,"dataGaName":1286,"dataGaLocation":2059},"https://gitlab.com/-/trial_registrations/new?glm_content=default-saas-trial&glm_source=about.gitlab.com/","feature",{"text":1760,"config":2061},{"href":1612,"dataGaName":1291,"dataGaLocation":2059},1786803752933]