Git
Chapters ▾ 2nd Edition

2.2 Základy práce se systémem Git - Nahrávání změn do repozitáře

Nahrávání změn do repozitáře

Nyní máte k dispozici opravdový gitový repozitář a pracovní kopii souborů projektu. Řekněme, že potřebujete udělat pár změn a zapsat snímky těchto změn do svého repozitáře pokaždé, když se projekt dostane do stavu, který chcete zaznamenat.

Zapamatujte si, že každý soubor ve vašem pracovním adresáři může být v jednou ze dvou stavů: sledován (tracked) a nesledován (untracked). Sledované soubory jsou ty soubory, které byly součástí posledního snímku. Mohou být ve stavu nezměněn (unmodified), změněn (modified) nebo připraven k zapsání (staged). Nesledované soubory jsou všechny ostatní, tedy veškeré soubory ve vašem pracovním adresáři, které nebyly obsaženy ve vašem posledním snímku a nenacházejí se v oblasti připravených změn. Po úvodním klonování repozitáře budou všechny vaše soubory sledované a nezměněné, protože je Git právě získal a dosud jste neudělali žádné změny.

Jakmile soubory editujete, začne je Git považovat za změněné, protože jste v nich od posledního zápisu revize provedli změny. Změněné soubory připravíte k zapsání (stage) a následně všechny připravené změny zapíšete (commit). A celý cyklus se opakuje.

Cyklus stavů vašich souborů.
Figure 8. Cyklus stavů vašich souborů.

Kontrola stavu souborů

Hlavním nástrojem na zjišťování stavu jednotlivých souborů je příkaz git status. Spustíte-li tento příkaz bezprostředně po klonování, objeví se zhruba následující:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

To znamená, že váš pracovní adresář je čistý. Jinými slovy, nejsou v něm žádné sledované soubory, které by byly změněny. Git také neví o žádných nesledovaných souborech, jinak by byly ve výčtu uvedeny. Příkaz vám dále sděluje, na jaké větvi (branch) se nacházíte, a informuje vás, že se neodchýlila od stejné větve na serveru. Prozatím budeme uvažovat, že jde o větev master, což je výchozí název (zatím se s tím nezatěžujte). V kapitole Větve v systému Git se větvemi a referencemi budeme zabývat podrobně.

Řekněme, že nyní přidáte do projektu nový soubor, například soubor README. Pokud soubor dříve neexistoval a vy spustíte příkaz git status, bude nesledovaný soubor uveden takto:

$ echo 'My Project' > README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Untracked files:
  (use "git add <file>..." to include in what will be committed)

    README

nothing added to commit but untracked files present (use "git add" to track)

Vidíte, že nový soubor README není sledován, protože je ve výpisu stavů uveden v části „Untracked files“. Není-li soubor sledován, znamená to, že Git vidí soubor, který nebyl v předchozím snímku (commit). Git ho nezařadí ani do dalších snímků, dokud mu k tomu nedáte výslovný příkaz. Díky tomu se nemůže stát, že budou do revizí nedopatřením zahrnuty vygenerované binární soubory nebo jiné soubory, které si nepřejete zahrnout. Vy si ale přejete soubor README do snímku zahrnout, a proto ho začněme sledovat.

Sledování nových souborů

K zahájení sledování nových souborů se používá příkaz git add. Sledování souboru README zahájíme takto:

$ git add README

Když znovu provedete příkaz git status, uvidíte, že je nyní soubor README sledován a připraven k zapsání:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Můžeme říci, že je připraven k zapsání, protože je uveden v části „Changes to be committed“, tedy „Změny k zapsání“. Pokud v tomto okamžiku zapíšete revizi (commit), bude do historického snímku uložena verze souboru z okamžiku, kdy jste spustili příkaz git add. Možná si vzpomínáte, že když jste před časem spustili příkaz git init, provedli jste potom příkaz git add (soubory). V příkazu git add je uvedena cesta buď k souboru, nebo k adresáři. Pokud se jedná o adresář, příkaz přidá rekurzivně všechny soubory v tomto adresáři.

Příprava změněných souborů k zapsání

Nyní provedeme změny v souboru, který už byl sledován. Pokud změníte už dříve sledovaný soubor s názvem CONTRIBUTING.md a poté znovu spustíte příkaz git status, zobrazí se něco takového:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Soubor CONTRIBUTING.md je uveden v části „Changes not staged for commit“ (změny, které nejsou připraveny k zapsání). Znamená to, že soubor, který je sledován, byl v pracovním adresáři změněn, avšak ještě nebyl připraven k zapsání (staged). K zapsání ho připravíme provedením příkazu git add. Příkaz git add je víceúčelový — používá se k zahájení sledování nových souborů, k přípravě souborů k zapsání a k dalším věcem, jako je například označení vyřešených případů kolize souborů při slučování. Možná vám pomůže, když o něm budete uvažovat spíše ve smyslu „přidej tento obsah do dalšího snímku“ než ve smyslu „přidej tento soubor do projektu“. Spusťme nyní příkaz git add, abychom soubor CONTRIBUTING.md připravili k zapsání, a potom znovu zadejme příkaz git status:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Oba soubory jsou nyní připraveny k zapsání a budou zahrnuty do příští revize. Nyní předpokládejme, že jste si vzpomněli na jednu malou změnu, kterou chcete v souboru CONTRIBUTING.md provést ještě před zapsáním revize. Soubor znovu otevřete, provedete změnu a chcete jej zapsat. Spusťme však ještě jednou příkaz git status:

$ vim CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Co to má být? Soubor CONTRIBUTING.md je uveden jak v části připraveno k zapsání (Changes to be committed), tak v části nepřipraveno k zapsání (Changes not staged for commit). Jak je tohle možné? Věc se má tak, že Git po spuštění příkazu git add připraví soubor k zapsání přesně ve tvaru, v jakém se nachází v daném okamžiku. Pokud nyní revizi zapíšete, stane se součástí snímku soubor CONTRIBUTING.md s obsahem, jaký měl, když jste naposledy spustili příkaz git add, a ne s obsahem, který měl v pracovním adresáři v okamžiku, kdy jste spustili příkaz git commit. Pokud upravíte soubor po provedení příkazu git add, je třeba spustit git add ještě jednou, aby byla k zápisu připravena aktuální verze souboru:

$ git add CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Zkrácený výpis stavu

Výstup příkazu git status je sice poměrně srozumitelný, ale je také dost ukecaný. Git nabízí použití příznaku pro zkrácený výpis stavu, který způsobí zobrazení změn v zhuštěné podobě. Pokud spustíte git status -s nebo git status --short bude výstup příkazu mnohem jednodušší:

$ git status -s
 M README
MM Rakefile
A  lib/git.rb
M  lib/simplegit.rb
?? LICENSE.txt

Před novými soubory, které nejsou sledované se zobrazuje ??, před novými soubory, které byly přidány do oblasti připravených k zapsání se zobrazuje A, před upravenými soubory se zobrazuje M (jako modified) atd. Na výstupu se zobrazují dva sloupce. Levý sloupec indikuje stav souboru v oblasti připravených změn (index, stage area), v pravém sloupci se indikuje stav v pracovním stromu. Takže například v uvedeném výstupu byl soubor README změněn v pracovním adresáři, ale nebyl zatím připraven k zápisu (staged), zatímco soubor lib/simplegit.rb byl změněn a připraven k zápisu. Soubor Rakefile byl změněn, připraven k zápisu a potom znovu změněn, takže se indikuje změna jak pro oblast připravenosti k zápisu, tak pro pracovní strom.

Ignorované soubory

Ve vašem adresáři se často vyskytne skupina souborů, u nichž nebudete chtít, aby je Git automaticky přidával nebo aby je vůbec uváděl jako nesledované. Jedná se většinou o automaticky vygenerované soubory, jako soubory log nebo soubory vytvořené při překladu. V takových případech můžete vytvořit soubor .gitignore se seznamem masek pro ignorované soubory. Zde je příklad souboru .gitignore:

$ cat .gitignore
*.[oa]
*~

První řádek Gitu říká, že se mají ignorovat všechny soubory končící na .o nebo .a — objekty a archivní soubory, které mohou být výsledkem překladu. Druhý řádek Gitu říká, aby ignoroval všechny soubory, jejichž jméno končí vlnovkou (~), kterou mnoho textových editorů (např. Emacs) používá k označení dočasných souborů. Můžete rovněž přidat adresáře log, tmp nebo pid, automaticky vygenerovanou dokumentaci a další. Většinou je dobré, když soubor .gitignore vytvoříte a naplníte ještě dříve, než se pustíte do práce. Díky tomu se vám nestane, že byste nedopatřením zapsali také soubory, o které v gitovém repozitáři nestojíte.

Pravidla pro masky, které můžete použít v souboru .gitignore, jsou následující:

  • Prázdné řádky nebo řádky začínající znakem # budou ignorovány.

  • Používají se standardní masky souborů (glob patterns).

  • Masku můžete zahájit lomítkem (/) a tím potlačíte rekurzivitu.

  • Masku můžete ukončit lomítkem (/) a tím vyjádříte, že jde o adresář.

  • Masku můžete negovat tím, že na začátku použijete vykřičník (!).

Masky souborů se podobají zjednodušeným regulárním výrazům, které znáte z shellu. Hvězdička (*) označuje žádný nebo více znaků; [abc] označuje jakýkoli znak uvedený v závorkách (v tomto případě a, b nebo c); otazník (?) označuje jeden znak; znaky v hranatých závorkách oddělené pomlčkou ([0-9]) označují jakýkoli znak v daném rozmezí (v našem případě 0 až 9). Použitím dvou hvězdiček můžeme popsat zanořené adresáře; a/**/z popisuje a/z, a/b/z, a/b/c/z a tak dále.

Další příklad souboru .gitignore:

# žádné soubory s příponou .a
*.a

# ale sleduj lib.a i přes to, že se výše uvedeným pravidlem mají .a ignorovat
!lib.a

# soubor TODO ignoruj jen tomto adresáři, ale neignoruj subdir/TODO
/TODO

# ignoruj všechny soubory v adresáři build/
build/

# ignoruje doc/notes.txt, ale ne doc/server/arch.txt
doc/*.txt

# ignoruj všechny .pdf soubory v adresáři doc/
doc/**/*.pdf
Tip

Pokud pro váš projekt potřebujete něco pro začátek, najdete na stránce https://github.com/github/gitignore serveru GitHub poměrně rozsáhlý seznam dobrých příkladů souboru .gitignore pro desítky projektů a jazyků.

Zobrazení připravených a nepřipravených změn

Pokud je pro vás příkaz git status příliš neurčitý — chcete přesně vědět, co jste změnili, nejen jaké soubory jste změnili --, můžete použít příkaz git diff. Podrobněji se budeme příkazu git diff věnovat později, ale nejčastěji ho budete využívat k zodpovězení těchto dvou otázek: Co jste změnili, ale ještě nepřipravili k zapsání? A co jste připravili k zapsání? Ačkoliv příkaz git status vám tyto otázky velmi obecně odpoví, příkaz git diff přesně zobrazí přidané a odstraněné řádky — jakoby v podobě záplaty.

Řekněme, že znovu upravíte a připravíte soubor README a poté upravíte soubor CONTRIBUTING.md, ale nepřipravíte jej k zápisu. Pokud provedete příkas git status, uvidíte opět něco takového:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   README

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Pokud chcete vidět, co jste změnili, ale zatím nepřipravili k zapsání, napište git diff bez dalších parametrů:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's

Tento příkaz porovná obsah vašeho pracovního adresáře s tím, co se nachází v oblasti připravených změn. Výsledek vám řekne, jaké změny jste provedli a dosud nepřipravili k zapsání.

Chcete-li vidět, co jste připravili a co bude součástí příští revize, použijte příkaz git diff --staged. Tento příkaz porovná změny připravené k zapsání vůči poslední zapsané revizi:

$ git diff --staged
diff --git a/README b/README
new file mode 100644
index 0000000..03902a1
--- /dev/null
+++ b/README
@@ -0,0 +1 @@
+My Project

Důležité je to, že git diff sám o sobě nezobrazí všechny změny provedené od poslední revize, ale jen změny, které zatím nejsou připraveny k zapsání. Může to být matoucí, protože pokud jste všechny provedené změny připravili k zapsání, bude výstup příkazu git diff prázdný.

Další příklad…​ Pokud jste soubor CONTRIBUTING.md připravili k zapsání a poté ho znovu upravili, můžete příkaz git diff použít k zobrazení změn v souboru, které byly připraveny k zapsání, a změn, které nejsou připraveny k zapsání. Dejme tomu, že situace vypadá následovně:

$ git add CONTRIBUTING.md
$ echo '# test line' >> CONTRIBUTING.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    modified:   CONTRIBUTING.md

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

Příkazem git diff se teď můžete podívat, co ještě není připraveno k zapsání:

$ git diff
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 643e24f..87f08c8 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -119,3 +119,4 @@ at the
 ## Starter Projects

 See our [projects list](https://github.com/libgit2/libgit2/blob/development/PROJECTS.md).
+# test line

a příkaz git diff --cached ukáže změny, které už jsou připraveny k zapsání (--staged a --cached jsou synonyma):

$ git diff --cached
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8ebb991..643e24f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -65,7 +65,8 @@ branch directly, things can get messy.
 Please include a nice description of your changes when you submit your PR;
 if we have to read the whole diff to figure out why you're contributing
 in the first place, you're less likely to get feedback and have your change
-merged in.
+merged in. Also, split your changes into comprehensive chunks if your patch is
+longer than a dozen lines.

 If you are starting to work on a particular area, feel free to submit a PR
 that highlights your work in progress (and note in the PR title that it's
Note
Git diff v externím nástroji

Ve zbytku knihy budeme příkaz git diff používat různými způsoby. Pokud vám víc vyhovují grafické nebo jiné externí programy pro prohlížení změn, pak tu máme další možnost. Pokud místo příkazu git diff spustíte git difftool, můžete si výslednou podobu rozdílů prohlížet v programech jako jsou emerge, vimdiff a další (včetně komerčních produktů). Pokud chcete vědět, co je pro váš systém k dispozici, spusťte git difftool --tool-help.

Zapisování změn

Nyní, když jste oblast připravených změn nastavili podle svých představ, můžete začít zapisovat změny (commit). Nezapomeňte, že všechno, co dosud nebylo připraveno k zapsání — všechny soubory, které jste vytvořili nebo změnili a pro které jste potom nepoužili git add --, nebudou do revize zahrnuty. Zůstanou na vašem disku jako změněné soubory. V tomto případě jste viděli (dejme tomu, když jste naposledy spustili git status), že vše bylo připraveno k zapsání, takže jste připraveni k samotnému zápisu. Nejjednodušší způsob spočívá v provedení git commit:

$ git commit

Po zadání příkazu se otevře vámi zvolený editor. (Ten je nastaven proměnnou prostředí $EDITOR vašeho shellu. Obvykle je to vim nebo emacs, ale příkazem git config --global core.editor můžete nastavit libovolný jiný — jak jsme viděli v kapitole Úvod).

Editor zobrazí následující text (tento příklad je z editoru Vim):

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Your branch is up-to-date with 'origin/master'.
#
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

Jak vidíte, výchozí zpráva k revizi obsahuje zakomentovaný aktuální výstup příkazu git status a nahoře jeden prázdný řádek. Tyto komentáře můžete odstranit a napsat vlastní zprávu k revizi, nebo je můžete v souboru ponechat, abyste si lépe vzpomněli, co vlastně zapisujete. (Chcete-li si ještě podrobněji připomenout, co jste měnili, můžete k příkazu git commit přidat parametr -v. V editoru se pak zobrazí také výstup rozdílů (diff), takže uvidíte přesně, jaké změny budete zapisovat.) Jakmile editor zavřete, Git vytvoří objekt revize se zprávou, kterou jste napsali (s odstraněnými komentáři, které zobrazovaly rozdíly).

Zprávu k revizi můžete rovněž napsat do řádku k příkazu commit. Jako zprávu ji označíte tak, že před ni vložíte příznak -m:

$ git commit -m "Story 182: Fix benchmarks for speed"
[master 463dc4f] Story 182: Fix benchmarks for speed
 2 files changed, 2 insertions(+)
 create mode 100644 README

Nyní jste vytvořili svou první revizi! Vidíte, že se po zapsání revize zobrazil výpis s informacemi: do jaké větve jste revizi zapsali (master), jaký má revize kontrolní součet SHA-1 (463dc4f), kolik souborů bylo změněno a statistiku přidaných a odstraněných řádků revize.

Nezapomeňte, že příkaz commit zaznamená snímek projektu, jak byl obsažen v oblasti připravených změn. Vše, co jste nepřipravili k zapsání, zůstane ve stavu změněno na vašem disku. Můžete provést další zápis a přidat to také do vaší historie. Pokaždé, když provedete příkaz commit, nahrajete snímek svého projektu, k němuž se můžete později vrátit nebo ho můžete použít k srovnání.

Přeskočení oblasti připravených změn

Oblast připravených změn může být úžasně užitečným nástrojem pro vytváření chtěné posloupnosti revizí, ale při určitém způsobu práce někdy představuje zbytečnou komplikaci. Chcete-li oblast připravených změn úplně přeskočit, nabízí Git jednoduchou zkratku. Přidáte-li k příkazu git commit parametr -a, Git do revize automaticky zahrne každý soubor, který je sledován. Odpadá potřeba zadávat příkaz git add:

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

    modified:   CONTRIBUTING.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git commit -a -m 'added new benchmarks'
[master 83e38c7] added new benchmarks
 1 file changed, 5 insertions(+), 0 deletions(-)

Povšimněte si, že kvůli souboru CONTRIBUTING.md v tomto případě nemusíte před zapsáním revize provádět příkaz git add. To proto, že příznak -a přidá všechny změněné soubory. Je to praktické, ale buďte opatrní. Někdy se stane, že si tímto příznakem přidáte nechtěné změny.

Odstraňování souborů

Chcete-li soubor z Gitu odstranit, musíte ho odstranit ze sledovaných souborů (přesněji řečeno, musíte ho odstranit z oblasti připravených změn) a poté zapsat revizi. Je k tomu určen příkaz git rm, který soubor odstraní také z vašeho pracovního adresáře, takže ho už příště neuvidíte mezi nesledovanými soubory.

Pokud soubor jednoduše odstraníte z pracovního adresáře, zobrazí se ve výpisu git status v části „Changes not staged for commit“ (tedy „Změny nejsou připraveny k zapsání“):

$ rm PROJECTS.md
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes not staged for commit:
  (use "git add/rm <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

        deleted:    PROJECTS.md

no changes added to commit (use "git add" and/or "git commit -a")

Pokud ale provedete git rm, odstranění souboru bude připraveno k zapsání:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    PROJECTS.md

Při příštím zápisu (commit) už tam soubor neuvidíte a nebude se sledovat. Pokud už jste soubor upravili a už jste ho přidali do indexu, musíte odstranění vynutit přidáním volby -f [6]. Jde o funkci zvyšující bezpečnost tím, že brání nechtěnému odstranění dat, která ještě nebyla zaznamenána do snímku, a proto by nemohla být Gitem obnovena.

Další užitečnou věcí, kterou byste mohli chtít, je možnost zachování souboru v pracovním stromu při současném odstranění z oblasti připravených změn. Jinými slovy, soubor chcete ponechat na disku, ale už nechcete, aby ho Git sledoval. Může to být zvlášť užitečné, pokud jste něco zapomněli přidat do souboru .gitignore a omylem jste to zahrnuli do oblasti připravených změn — například velký log soubor nebo spoustu zkompilovaných souborů s příponou .a. Provedete to pomocí volby --cached:

$ git rm --cached README

Příkazu git rm můžete zadat soubory, adresáře a jejich masky. To znamená, že můžete zadat příkaz jako:

$ git rm log/\*.log

Všimněte si zpětného lomítka (\) před znakem *. Je to nezbytné, protože Git provádí své vlastní nahrazování masek souborů (kromě toho, které provádí shell). Uvedeným příkazem odstraníte všechny soubory s příponou .log z adresáře log/. Provést můžete také tento příkaz:

$ git rm \*~

Tento příkaz odstraní všechny soubory, jejichž jména končí vlnovkou (~).

Přesouvání souborů

Na rozdíl od ostatních systémů pro správu verzí, Git nesleduje přesouvání souborů přímo. Pokud soubor v systému Git přejmenujete, neuloží se žádná metadata s informací, že jste soubor přejmenovali. Nicméně, Git je dost chytrý na to, aby to zjistil. Detekcí přesunu souboru se budeme zabývat později.

Takže se může zdát zvláštní, že Git přesto nabízí příkaz mv. Chcete-li v systému Git přejmenovat soubor, můžete provést něco takového:

$ git mv stare_jmeno_souboru nove_jmeno_souboru

a vše bezvadně funguje. A skutečně, pokud takový příkaz provedete a podíváte se na hlášení o stavu, uvidíte, že Git považuje soubor za přejmenovaný (renamed):

$ git mv README.md README
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Výsledek je však stejný, jako byste provedli následující:

$ mv README.md README
$ git rm README.md
$ git add README

Git umí zjistit, že jde o přejmenování, a proto nehraje roli, zda přejmenujete soubor tímto způsobem, nebo pomocí příkazu mv. Jediným skutečným rozdílem je, že git mv je jediný příkaz místo tří — jde o funkci pro zjednodušení práce. Důležitější je, že pro přejmenování souboru můžete použít jakýkoli oblíbený nástroj a později, před zapsáním revize, provést příkaz add/rm.