Varför Git är bättre än X

Denna sida är här för att jag ofta måste spendera tid med att försvara Git-användare från anklagelser om att vara partiska, favoritiserande och att de bara väljer Git eftersom det är populärt att välja. Här är de riktiga skälen till att folk byter till Git från X, och varför du också borde det. Klicka på ett argument för att se det.

hg bzr svn perforce

Billig lokal förgrening (branching)

Antagligen är Gits mest intressanta egenskap som skiljer sig från nästan alla versionhanteringssystem (SCM) dess branchingstöd. Det är helt annorlunda alla andra system som vi jämför med här, där de flesta egentligen hanterar grenar som en kopia av hela arkivet i en annan mapp.
Git fungerar inte på detta sätt. Git tillåter dig att ha ett flertal lokala grenar som kan vara helt oberoende av varandra och att skapa, slå ihop och ta bort dem tar sekunder.
Detta betyder att du kan göra saker som att
  • skapa en gren för att prova en idé du har, checka in ändringar hur mycket du vill, gå tillbaka till där du var innan, verkställa en patch, gå tillbaka till ditt experiment och till sist slå ihop grenen.
  • ha en gren som alltid innehåller det som är produktionssatt, en annan där du har det som skall testas och flera mindre för dagligt arbete.
  • skapa en ny gren för varje ny funktionalitet du arbetar på så du kan sömlöst hoppa mellan dem, och sedan ta bort grenar som redan slagits ihop med din huvudgren.
  • skapa en gren att experimentera i, inse att det inte ledde till något konkret och sedan ta bort den och överge ditt arbete – utan att någon annan har fått se den, trots att du kan ha tryckt ut ändringar i andra grenar under tiden.
Viktigt att förstå är att när du trycker ut dina ändringar till ett externt arkiv så måste du inte också trycka ut alla dina grenar. Du kan bara dela med dig av en gren, inte alla. Detta brukar ge många möjlighet att experimentera med saker utan att direkt behöva oroa sig för hur och när de ska dela med sig av experimentet till andra.
Du kan komma på sätt att göra detta med några av de andra systemen, men arbetet som skulle vara associerat med dem är mycket svårare och kan gå fel lättare. Git gör denna process otroligt enkel och det förändrar hur de flesta utvecklare arbetar när de lärt sig detta.
jamis twitter trevorturk twitter thillerson twitter boblmartens twitter mathie twitter
svn perforce

Allt är lokalt

Detta är egentligen ganska sant med alla distribuerade SCM:er, men enligt mina erfarenheter så är det extra sant med Git. Det är lite utöver "fetch", "pull" och "push" som kommunicerar på något sätt med något annat än din egen hårddisk.
Detta gör inte bara det mesta operationer snabbare än vad du kanske förväntar dig, utan gör också att du kan arbeta med saker utan en uppkoppling. Det kanske inte låter som en stor sak, men jag blir alltid förundrad över hur ofta jag faktiskt jobbar frånkopplat. Att kunna förgrena, slå ihop grenar, checka in ändringar och se historik samtidigt som du sitter i ett tåg eller ett flygplan är väldigt produktivt.
Även i Mercurial så kommunicerar vanliga kommandon som "incoming" och "outgoing" med en server, medan du med Git kan göra en "fetch" och sedan ha all data från servern, vilket ger dig möjligheten att hantera kod som du inte har i dina lokala grenar än, trots att du är frånkopplad.
Detta betyder således att det är mycket enkelt att ha kopior av inte bara dina grenar, utan också grenarna som tillhör de andra som jobbar i samma arkiv utan att det stökar till dina egna ändringar och grenar.
bzr svn perforce

Git är snabbt

Git är snabbt. Alla — till och med de mest inbitna fansen av de andra systemen — brukar ge Git denna titel. Med Git sker alla operationer lokalt, vilket ger en klart snabbare körning än SVN och Perforce som båda kräver en anslutning till en server för många kommandon. Men även om man jämför med de andra distribuerade SCM:arna så är Git ganska snabbt.
Ett skäl till detta är antagligen eftersom Git byggdes för arbete på Linuxkärnan, vilket innebär att det fanns behov av att det skulle kunna hantera stora arkiv effektivt redan från första början. Dessutom är Git skrivet i C, vilket minskar på allt extra resursanvändande som är associerat med att ha en applikation skriven i ett mer högnivåspråk. Ett till skäl till att Git är snabbt är att utvecklarna haft detta som ett mål med applikationen och därför utvecklat Git för det.
Följande är ett antal mätningar jag gjorde där jag mätte hastigheten på ett antal operationer i kopior av Django- arkivet i olika SCM:er, nämligen Git, Mercurial och Bazaar. Jag provade också med Subversion, och tro mig: Det är långsammast – ta Bazaars nummer och lägg till nätverksfördröjningar.
Slutresultatet var att för allt utom att lägga till nya filer så var Git snabbast. (Även riktigt stora incheckningar, som Hg var lika snabb på, men den incheckning som jag provade var så stor att du antagligen aldrig kommer att göra en sådan själv – vanliga incheckningar är mycket snabbare än så i Git)
Git Hg Bzr
Init (Skapande) 0.024s 0.059s 0.600s
Add (Lägga till) 8.535s 0.368s 2.381s
Status 0.451s 1.946s 14.744s
Diff (Se förändringar) 0.543s 2.189s 14.248s
Tag (Märka) 0.056s 1.201s 1.892s
Log (Historik) 0.711s 2.650s 9.055s
Commit (Incheckning, stor) 12.480s 12.500s 23.002s
Commit (Incheckning, liten) 0.086s 0.517s 1.139s
Branch (Skapa gren, kall) 1.161s 94.681s 82.249s
Branch (Skapa gren, varm) 0.070s 12.300s 39.411s
Den varma och kalla förgreningen är de nummer som jag fick första och andra gången jag gjorde en ny gren – den andra är med en varm diskcache.
Det bör noteras att de höga siffrorna för att lägga till filer i arkivet trots allt var mycket stora listor med filer – över 2 000 av dem. För majoriteten av allt användande så kommer alla "add" operationer köras på mycket mindre listor än detta, och då tar hela operationen hundradelar av en sekund i alla dessa system. Alla andra testade operationer här är mer representativa för vad dagligt användande går ut på.
Dessa nummer är inte svåra att återskapa, bara klona Django-arkiven genom de olika systemen och prova samma kommandon i dem alla.
  • git clone git://github.com/brosner/django.git dj-git
  • hg clone http://hg.dpaste.com/django/trunk dj-hg
  • bzr branch lp:django dj-bzr
  • svn checkout http://code.djangoproject.com/svn/django/trunk dj-svn
svn

Git is Small

Git is really good at conserving disk space. Your Git directory will (in general) barely be larger than an SVN checkout — in some cases actually smaller (apparently a lot can go in those .svn dirs).
The following numbers were taken from clones of the Django project in each of its semi-official Git mirrors at the same point in its history.
Git Hg Bzr Bzr* SVN
Repo Alone 24M 34M 45M 89M
Entire Directory 43M 53M 64M 108M 61M
* the second Bzr number is after I ran 'bzr pack', which I thought would make it smaller, but ended up making it much, much larger for some reason.
hg bzr svn perforce

The Staging Area

Unlike the other systems, Git has what it calls the "staging area" or "index". This is an intermediate area that you can setup what you want your commit to look like before you commit it.
The cool thing about the staging area, and what sets Git apart from all these other tools, is that you can easily stage some of your files as you finish them and then commit them without committing all the modified files in your working directory, or having to list them on the command line during the commit
This also allows you to stage only portions of a modified file. Gone are the days of making two logically unrelated modifications to a file before you realized that you forgot to commit one them. Now you can just stage the change you need for the current commit and stage the other change for the next commit. This feature scales up to as many different changes to your file as you need.
Of course, Git also makes it pretty easy to ignore this feature if you don't want that kind of control — just slap a '-a' to your commit command in order to add all changes to all files to the staging area.
svn perforce

Distributed

One of the coolest features of any of the Distributed SCMs, Git included, is that it's distributed. This means that instead of doing a "checkout" of the current tip of the source code, you do a "clone" of the entire repository.
This means that even if you're using a centralized workflow, every user has what is essentially a full backup of the main server, each of which could be pushed up to replace the main server in the event of a crash or corruption. There is basically no single point of failure with Git unless there is only a single point.
This does not slow things down much, either. On average, an SVN checkout is only marginally faster than any of the DSCMs. Of the DSCMs I tested, Git was the fastest.
Git 1m 59s
Hg 2m 24s
Bzr 5m 11s
SVN 1m 4s
svn perforce

Any Workflow

One of the amazing things about Git is that because of its distributed nature and super branching system, you can easily implement pretty much any workflow you can think of relatively easily.

Subversion-Style Workflow

A very common Git workflow, especially from people transitioning from a centralized system, is a centralized workflow. Git will not allow you to push if someone has pushed since the last time you fetched, so a centralized model where all developers push to the same server works just fine.

Integration Manager Workflow

Another common Git workflow is where there is an integration manager — a single person who commits to the 'blessed' repository, and then a number of developers who clone from that repository, push to their own independent repositories and ask the integrator to pull in their changes. This is the type of development model you often see with open source or GitHub repositories.

Dictator and Lieutenants Workflow

For more massive projects, you can setup your developers similar to the way the Linux kernel is run, where people are in charge of a specific subsystem of the project ('lieutenants') and merge in all changes that have to do with that subsystem. Then another integrator (the 'dictator') can pull changes from only his/her lieutenants and the push to the 'blessed' repository that everyone then clones from again.

Again, Git is entirely flexible about this, so you can mix and match and choose the workflow that is right for you.
hg bzr svn perforce

GitHub

I may be biased here, given that I work for GitHub, but I add this section anyway because so many people say that GitHub itself was specifically why they choose Git.
GitHub is a reason to use Git for many people because it is more like a social network for code than a simple hosting site. People find other developers or projects that are similar to the things they are doing, and can easily fork and contribute, creating a very vibrant community around Git and the projects that people use it for.
There exist other services, both for Git and for the other SCMs, but few are user-oriented or socially targeted, and none have anywhere near the user-base. This social aspect of GitHub is killer, and this in combination of the above features make working with Git and GitHub a great combination for rapidly developing open source projects.
This type of community is simply not available with any of the other SCMs.
puls twitter twitter
perforce

Easy to Learn

This did not used to be true — early in Git's life, it was not really an SCM so much as a bunch of tools that let you do versioned filesystem work in a distributed manner. However, today, the command set and learning curve of Git are pretty similar to any other SCM, and even better than some.
Since this is difficult to prove objectively without some sort of study, I'll just show the difference between the default 'help' menu for the Mercurial and Git commands. I've highlighted the commands that are identical (or nearly) between the two systems. (In Hg, if you type 'hg help', you get a list of 40-some commands.)

Mercurial Help

add        add the specified files ...
annotate   show changeset informati...
clone      make a copy of an existi...
commit     commit the specified fil...
diff       diff repository (or sele...
export     dump the header and diff...
init       create a new repository ...
log        show revision history of...
merge      merge working directory ...
parents    show the parents of the ...
pull       pull changes from the sp...
push       push changes to the spec...
remove     remove the specified fil...
serve      export the repository vi...
status     show changed files in th...
update     update working directory

Git Help

add        Add file contents to the index
bisect     Find the change that introduce...
branch     List, create, or delete branches
checkout   Checkout a branch or paths to ...
clone      Clone a repository into a new ...
commit     Record changes to the repository
diff       Show changes between commits, ...
fetch      Download objects and refs from...
grep       Print lines matching a pattern
init       Create an empty git repository
log        Show commit logs
merge      Join two or more development h...
mv         Move or rename a file, a direc...
pull       Fetch from and merge with anot...
push       Update remote refs along with ...
rebase     Forward-port local commits to ...
reset      Reset current HEAD to the spec...
rm         Remove files from the working ...
show       Show various types of objects
status     Show the working tree status
tag        Create, list, delete or verify...
Prior to Git 1.6, all of the Git commands used to be in the executable path, which was very confusing to people. Although Git still recognizes all of those commands, the only command in the path is now 'git'. So, if you look at Mercurial and Git, Git has a nearly identical command set and help system — there is very little difference from a beginning UI perspective today.
These days it's pretty hard to argue that Mercurial or Bazaar is any easier to learn than Git is.