Git
Chapters ▾ 2nd Edition

2.2 Osnove Git - Snemanje sprememb repozitorija

Snemanje sprememb repozitorija

Imate izdelan repozitorij Git in izpis ali delovno kopijo datotek za ta projekt. Narediti moreate nekaj sprememb in poslati posnetke teh sprememb v vaš repozitorij vsakič, ko projekt doseže stanje, ki ga želite posneti.

Pomnite, da je lahko vsaka datoteka v vašem delovnem direktoriju v dveh stanjih: sledena ali nesledena. Sledene datoteke so datoteke, ki so bile v zadnjem posnetku; so lahko nespremenjene, spremenjene ali dane v vmesno fazo. Nesledene datoteke so vse ostale - katerakoli datoteka v vašem delovnem direktoriju, ki ni bila v vašem zadnjem posnetku in ni v vašem področju vmesne faze. Ko prvič klonirate repozitorij, bodo vse vaše datoteke sledene in nespremenjene, ker ste jih ravnokar izpisali in jih niste kakorkoli urejali.

Kot boste urejali datoteke, jih Git vidi kot spremenjene, ker ste jih spremenili od zadnjega pošiljanja. Te spremenjene datoteke date v vmesno fazo in nato pošljete vse vaše spremembe v vmesni fazi in cikel se ponovi.

The lifecycle of the status of your files.
Figure 8. The lifecycle of the status of your files.

Preverjanje status vaših datotek

Glavno orodje, ki ga uporabljate, da določite katere datoteke so v kakšnem stanju je ukaz git status. Če ta ukaz poženete direktno po kloniranju, bi morali videti nekaj takega:

$ git status
On branch master
nothing to commit, working directory clean

To pomeni, da imate čisti delovni direktorij - z drugimi besedami, ni sledenih ali spremenjenih datotek. Git tudi ne vidi kakršnihkoli nesledenih datotek, drugače bi bile tu izpisane. Končno ukaz vam pove na kateri veji ste in vas obvesti, da ne izhaja iz iste veje na strežniku. Za sedaj je ta veja vedno “master”, kar je privzeto; o tem ne boste tu skrbeli. Veje Git bo šlo čez veje in reference v podrobnosti.

Recimo, da dodate novo datoteko v vaš projekt, enostavna datoteka README. Če datoteka prej še ni obstajala, in poženete git status, boste videli vašo nesledeno datoteko kot:

$ echo 'My Project' > README
$ git status
On branch 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)

Vidite lahko, da vaša nova datoteka README ni sledena, ker je pod “Untracked files”, ki kaže v vaš izpis statusa. Nesledeno v osnovi pomeni, da Git vidi datoteko, ki je niste imeli v prejšnjem posnetku (commit); Git je ne bo začel vključevati v vaše poslane posnetke dokler mu tega eksplicitno ne poveste.

To dela zato, da po ne sreči ne začnete vključevati generiranih binarnih datotek ali ostalih datotek, ki jih niste mislili vključiti. Hoteli boste začeti vključiti README, tako da začnimo s sledenjem datoteke.

Tracking New Files

Da začnete slediti novi datoteki, uporabite ukaz git add. Da začnete slediti datoteki README, lahko poženete sledeče:

$ git add README

Če ponovno poženete vaš ukaz statusa, lahko vidite, da je vaša datoteka README sedaj sledena in dana v vmesno fazo za pošiljanje:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README

Lahko poveste, da je dana v vmesno fazo, ker je pod glavo “Changes to be committed”. Če pošljete na tej točki, bo verzija datoteke v času, ko ste pognali git add v zgodovini posnetka. Morda se spomnite, da ko ste prej pognali git init, ste nato pognali git add (files) - to je bil začetek sledenja datotek v vašem direktoriju.

Ukaz git add vzame ime poti za ali datoteko ali direktorij; če je direktorij, ukaz doda vse datoteke v tem direktoriju rekurzivno.

Staging Modified Files

Spremenimo datoteko, ki je bila že sledena. Če spremenite prej sledeno datoteko imenovano “CONTRIBUTING.md” in nato poženete vaš git status ukaz ponovno, dobite nekaj, kar izgleda takole:

$ git status
On branch 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

Datoteka “CONTRIBUTING.md” se pojavi pod sekcijo imenovano “Changed but not staged for commit” - kar pomeni, da je sledena datoteka bila spremenjena v delujočem direktoriju, vendar še ni bila dana v vmesno fazo. Za dodajanje v vmesno fazo, poženete ukaz git add. git add je ukaz z večimi pomeni - uporabite ga za začetek sledenja novih datotek, da date datoteke v vmesno fazo in naredite druge stvari kot je označevanje konfliktov združevanja za rešene. Lahko je v pomoč razmišljanje o tem bolj v smislu “dodajte to vsebino naslednjemu pošiljanju” kot pa “dodajte to datoteku projektu”. Poženimo git add sedaj za dajanje v vmesno fazo datoteki “CONTRIBUTING.md” in nato ponovno poženimo git status:

$ git add CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Obe datoteki sta dani v vmesno fazo in bosta šli v vaše naslednje pošiljanje. Na tej točki predpostavimo, da se spomnite neke majhne spremembe, ki jo želite narediti v CONTRIBUTING.md preden jo pošljete. Ponovno jo odprete in naredite to spremembo in že ste pripravljeni na pošiljanje. Vendar poženimo git status še enkrat:

$ vim CONTRIBUTING.md
$ git status
On branch 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

Kaj za vraga? Sedaj je CONTRIBUTING.md izpisan tako kot vmesna faza kot tudi brez vmesne faze. Kako je to mogoče? Izkaže se, da Git da datoteko v vmesno fazo točno tako kot je, ko poženete ukaz git add. Če pošljete sedaj, bo verzija CONTRIBUTING.md kakršna je bila, ko ste nazadnje pognali ukaz git add in bo šla v pošiljanje, ne pa verzija datoteke kot izgleda v vašem delovnem direktoriju, ko poženete ukaz git commit. Če spremenite datoteko po tem, ko poženete git add, morate pognati git add ponovno, da date v vmesno fazo zadnjo verzijo datoteke:

$ git add CONTRIBUTING.md
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    new file:   README
    modified:   CONTRIBUTING.md

Kratek status

Medtem ko je izpis git status precej celovit, je tudi precej gostobeseden. Git ima tudi kratko zastavico statusa, da lahko vidite vaše spremembe na bolj kompakten način. Če poženete git status -s ali git status --short dobite veliko bolj poenostavljen izpis iz ukaza.

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

Nove datoteke, ki niso sledene imajo zraven njih ??, nove datoteke, ki so bile dodane v vmesno fazo imajo A, spremenjene datoteke imajo M in tako dalje. Obstajata dva stolpca za izpis - levi stolpec označuje, da je bila datoteka dana v vmesno fazo in desni stolpec označuje, da je spremenjena. Torej na primer v tem izpisu je datoteka README spremenjena v delovnem direktoriju, vendar še ni dana v vmesno fazo, medtem kot je datoteka lib/simplegit.rb spremenjena in dana v vmesno fazo. Rakefile je bila spremenjena, dana v vmesno fazo in nato ponovno spremenjena, torej so spremembe na njej, ki so tako dane v vmesno fazo in ne.

Ignoriranje datotek

Pogostokrat boste imeli razred datotek, ki jih ne želite, da jih Git avtomatično doda ali celo prikazuje kot sledene. Te so v splošnem avtomatsko generirane datoteke, kot so datoteke dnevnika ali datoteke producirane z vašim sistemom gradnje. V teh primeriih lahko ustvarite vzorec seznama datotek, ki se ujema z imeni .gitignore. Tu je primer .gitignore datoteke:

$ cat .gitignore
*.[oa]
*~

Prva vrstica pove Git-u, naj ignorira katerekoli datoteke, ki se končajo z “.o” ali “.a” - objekti in arhivske datoteke, ki so lahko produkt gradnje vaše kode. Druga vrstica pove Git-u naj ignorira vse datoteke, ki se končajo s tildo (~), ki je uporabljena s strani mnogih tekstovni urejevalnikov kot je Emacs, da označuje začasne datoteke. Lahko tudi vključite dnevnik, tmp ali pid direktorij; avtomatsko generirano dokumentacijo; itd. Nastavitev .gitignore datoteke preden pričnete je v splošnem dobra ideja, da po ne sreči ne pošljete datotek, ki jih v resnici ne želite imeti v vašem Git repozitoriju.

Pravila vzorcev, ki jih lahko vključite v .gitignore datoteki so sledeča:

  • Prazne vrstice ali vrstice, ki se začnejo z # so ignorirane.

  • Standardni glob vzorci delujejo.

  • Vzorce lahko začnete poševnico (/), da se izognete rekurziji.

  • Lahko zaključite vzorce s poševnico (/), da določite direktorij.

  • Lahko negirate vzorec tako, da ga začnete s klicajem (!).

Glob vzorci so verjetno poenostavljeni splošni izrazi, ki jih lupina uporablja. Zvezdica (*) se ujema z nič ali več znaki; [abc] se ujema s katerimkoli znakom znotraj oglatih oklepajev (v tem primeru a, b, ali c); vprašaj (?) se ujema z enim znakom; in zavitimi oklepaji, ki zapirajo znake ločene s pomišljaji ([0-9]) se ujema s katerim koli znakom med njimi (v tem primeru 0 do 9). Lahko uporabite dve zvezdice, da se ujema direktorije; a/**/z se ujema z a/z, a/b/z a/b/c/z itd.

Tu je drug primer datoteke .gitignore:

# no .a files
*.a

# but do track lib.a, even though you're ignoring .a files above
!lib.a

# only ignore the TODO file in the current directory, not subdir/TODO
/TODO

# ignore all files in the build/ directory
build/

# ignore doc/notes.txt, but not doc/server/arch.txt
doc/*.txt

# ignore all .txt files in the doc/ directory
doc/**/*.txt
Tip

GitHub upravlja precej zgoščen seznam dobrih primerov .gitignore datotek za ducate projektov in jezikov na https://github.com/github/gitignore, če želite začetno točko za vaš projekt.

Ogled vaših sprememb v vmesni fazi in izven vmesne faze

Če je ukaz git status za vas preveč nejasen - želite vedeti točno, kaj ste spremenili, ne samo katere datoteke so bile spremenjene - lahko uporabite ukaz git diff. git diff bomo pokrili v več podrobnostih kasneje, vendar ga boste uporabljali najpogosteje za odgovor na ti dve vprašanji: Kaj ste spremenili vendar še ni dano v vmesno fazo? In kaj ste dali v vmesno fazo, da boste poslali? Čeprav git status odgovori ta vprašanja zelo splošno z izpisom seznama imen datotek, vam git diff prikaže točne vrstice, ki so bile dodane in odstranjene - popravek kot je bil.

Recimo, da urejate in dajete v vmesno fazo datoteko README in nato uredite datoteko CONTRIBUTING.md brez dajanja v vmesno fazo. Če poženete vaš ukaz git status, ponovno vidite nekaj takega:

$ git status
On branch 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

Da vidite, kaj ste spremenili, vendar ni še dano v vmesno fazo, vtipkajte git diff brez nobenih argumentov:

$ 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

Ukaz primerja, kaj je v vašem delovnem direktoriju s tem, kar je v vaši vmesni fazi. Rezultat vam pove spremembe, ki ste jih naredili in ki niso še dane v vmesno fazo.

Če želite videti, kaj ste dali v vmesno fazo in bo šlo v vaše naslednje pošiljanje, lahko uporabite git diff --staged. Ta ukaz primerja vaše spremembe dane v vmesno fazo z vašim zadnjim pošiljanjem:

$ 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

Pomembno je omeniti, da git diff sam po sebi ne prikazuje vseh sprememb, narejenih od vašega zadnjega pošiljanja - samo spremembe, ki še vedno niso dane v vmesno fazo. To je lahko zmedeno, ker če ste dali v vmesno fazo vse vaše spremembe, git diff ne bo dal nobenega izpisa.

Za drug primer, če date datoteko CONTRIBUTING.md v vmesno fazo in jo nato uredite, lahko uporabite git diff, da vidite spremembe v datoteki, ki je dana v vmesno fazo in spremembe, ki še niso dane v vmesno fazo. Če naše okolje izgleda takole:

$ git add CONTRIBUTING.md
$ echo 'test line' >> CONTRIBUTING.md
$ git status
On branch 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

Sedaj lahko uporabite git diff, da vidite, kaj še vedno ni dano v vmesno fazo

$ 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

in git diff --cached, da vidite, kaj ste dali v vmesno fazo do sedaj (--staged in --cached sta sinonima):

$ 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 in an External Tool

Nadaljevali bomo z uporabo ukaza git diff na različne načine skozi preostanek knjige. Je še drug način pogledati te spremembe, če imate raje grafično ali zunanji diff pregledovalnik namesto tega. Če poženete git difftool namesto git diff, lahko pogledate katerekoli od teh sprememb v programu kot je Araxis, emerge, vimdiff in več. Poženite git difftool --tool-help, da vidite, kaj je na voljo na vašem sistemu.

Pošiljanje vaših sprememb

Sedaj, ko je vaša vmesna faza nastavljena na način, kot ga želite, lahko pošljete vaše spremembe. Pomnite, da karkoli, kar še ni dano v vmesno fazo - katerekoli datoteke, ki ste jih ustvarili ali spremenili in na njih še niste pognali git add odkar ste jih uredili - ne bodo šle v to pošiljanje. Ostale bodo nespremenjene datoteke na vašem disku. V tem primeru, recimo, da zadnjič, ko ste pognali git status, ste videli, da je vse dano v vmesno fazo, torej ste pripravljeni, da pošljete vaše spremembe. Najenostavnejši način za pošiljanje je vpis git commit:

$ git commit

To zažene vaš urejevalnik po izbiri. (To je nastavljeno v vaši spremenljivki okolja $EDITOR lupine - običajno vim ali emacs, vendar lahko nastavite s čimerkoli želite z uporabo git config --global core.editor ukazom kot ste videli v Pričetek).

Urejevalnik prikaže sledeči tekst (ta primer je Vim zaslon):

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

Vidite lahko, da privzeto sporočilo pošiljanja vsebuje zadnji izpis ukaza git status, ki je zakomentiran in ima eno prazno vrstico na vrhu. Te komentarje lahko odstranite in vpišete vaše sporočilo pošiljanja, ali jih pustite tam, da vam pomagajo se spomniti, kaj pošiljate. (Za še bolj eksplicitni opomnik, kaj ste spremenili, lahko podate opcijo -v k git commit. To tudi doda razliko vaše spremembe v urejevalnik, da lahko točno vidite, katere spremembe pošiljate.) Ko zapustite urejevalnik, Git ustvari vaše pošiljanje s sporočilom pošiljanja (s komentarji in odstranjeno razliko).

Alternativno lahko vpišete vaše sporočilo pošiljanja v vrsticah z ukazom commit, ki ga določite po zastavicit -m, takole:

$ 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

Sedaj ste ustvarili vaše prvo pošiljanje! Lahko vidite, da vam je pošiljanje dalo izpis o samem sebi: v katero vejo ste poslali (master), katera je SHA-1 preverjena vsota, ki jo pošiljanje ima (463dc4f), koliko datotek je bilo spremenjenih in statistiko o dodanih in odstranjenih vrsticah v pošiljanju:

Zapomnite si, da pošiljanje snema posnetke, ki ste jih nastavili v vaši vmesni fazi. Karkoli, kar niste dali v vmesno fazo, še vedno čaka spremenjeno; lahko naredite drugo pošiljanje, da to dodate v vašo zgodovino. Vsakič, ko izvedete pošiljanje, snemate posnetek vašega projekta, ki ga lahko povrnete ali primerjate kasneje.

Preskočitev vmesne faze

Čeprav je posebej uporabna za izdelovanje pošiljanj točno tako, kakor jih želite, je vmesna faza včasih bolj kompleksna, kot jo potrebujete v vašem poteku dela. Če želite preskočiti vmesno fazo, Git ponuja enostavno bližnjico. Dodajanje opcije -a ukazu git commit naredi, da Git avtomatično da vsako datoteko, ki je že sledena preden naredi pošiljanje in vam omogoči preskočiti del git add:

$ git status
On branch 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(-)

Bodite pozorni, kako vam ni treba pognati git add na datoteki “CONTRIBUTING.md” v tem primeru pred vašim pošiljanjem.

Odstranjevanje datotek

Da odstranite datoteko iz Git-a, jo morate odstraniti iz vaših sledenih datotek (bolj točno, odstraniti iz vaše vmesne faze) in nato poslati. Ukaz git rm naredi to in tudi odstrani datoteko iz vašega delovnega direktorija, da je ne vidite kot nesledeno datoteko v naslednjem času.

Če enostavno odstranite datoteko iz vašega delovnega direktorija se prikaže pod “Changed but not updated” (to je unstaged) področju vašega izpisa git status:

$ 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")

Nato, če poženete git rm da odstranjevanje datoteke v vmesno fazo:

$ git rm PROJECTS.md
rm 'PROJECTS.md'
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    PROJECTS.md

Naslednjič, ko pošiljate, bo datoteka odstranjena in ne bo več sledena. Če ste spremenili datoteko in jo že dodali v indeks, morate prisiliti odstranjevanje z opcijo -f. To je varnostna lastnost, da prepreči po nesreči odstranjevanje podatkov, ki še niso bili posneti v posnetku in ne morejo biti povrnjeni iz Git-a.

Druga uporabna stvar, ki jo morda želite narediti je slediti datoteki v vašem delovnem drevesu, vendar odstraniti iz vaše vmesne faze. Z drugimi besedami, morda želite slediti datoteki na vašem trdem disku vendar vam je ni treba slediti. To je posebej uporabno, če pozabite dodati nekaj v vašo datoteko .gitignore in jo po nesreči date v vmesno fazo, kot je velika datoteka dnevnika ali skupek prevedenih datotek .a. Da to naredite, uproabite opcijo --cached:

$ git rm --cached README

Lahko podate datoteke, direktorije in vzorce datotek-glob k ukazu git rm. To pomeni, da lahko naredite stvari kot je

$ git rm log/\*.log

Bodite pozorni na obratno poševnico (\) na začetku *. To je potrebno, ker Git dela svoje lastno razširjanje imen datotek k dodatku vašega razširjanja imen datotek lupine. Ta ukaz odstrani vse datoteke, ki imajo razširitev .log v direktoriju log/. Ali pa lahko naredite nekaj takega:

$ git rm \*~

Ta ukaz odstrani vse datoteke, ki se končajo z ~.

Premikanje datotek

Z razliko od ostalih sistemov VCS, Git eksplicitno ne sledi premikanju datotek. Če v Git-u preimenujete datoteko, niso nobenih metapodatki shranjeni v Git, da vam pove, da ste preimenovali datoteko. Vendar je Git precej pameten glede ugotavljanja po dejstvu - z detekcijo premikanja datotek se bomo ukvarjali nekoliko kasneje.

Torej je nekoliko nejasno, da Git ima ukaz mv. Če želite preimenovati datoteko v Git-u, lahko poženete nekaj takega

$ git mv file_from file_to

in deluje odlično. V bistvu, če poženete nekaj takega in pogledate status, boste videli, da Git smatra kot preimenovano datoteko:

$ git mv README.md README
$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    renamed:    README.md -> README

Vendar to je ekvivalentno pogonu nečesa takega:

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

Git ugotovi, da gre za preimenovanje implicitno, torej ni pomembno, če preimenujete datoteko na ta način ali z ukazov mv. Edina realna razlika je, da mv je en ukaz namesto treh - gre za funkcijo udobja. Bolj pomembno, lahko uporabite katerokoli orodje želite za preimenovanje datoteke in naslovite add/rm kasneje, preden pošljete.