Git
Chapters ▾ 2nd Edition

2.2 Τα θεμελιώδη στοιχεία του Git - Καταγραφή αλλαγών στο αποθετήριο

Καταγραφή αλλαγών στο αποθετήριο

Έχουμε λοιπόν ένα ολοκαίνουριο αποθετήριο Git και μια ενημερωμένη έκδοση των αρχείων του έργου. Η διαδικασία που θα ακολουθήσουμε είναι να κάνουμε μερικές αλλαγές στο έργο και να υποβάλλουμε ένα στιγμιότυπο από αυτές τις αλλαγές στο αποθετήριο κάθε φορά που θέλουμε να καταγράψουμε την εκάστοτε κατάσταση του έργου μας.

Οποιοδήποτε αρχείο στον κατάλογο που δουλεύουμε μπορεί να βρίσκεται σε δύο καταστάσεις: παρακολουθούμενο ή μη-παρακολουθούμενο. Τα παρακολουθούμενα αρχεία είναι αυτά που βρίσκονταν στο τελευταίο στιγμιότυπο και μπορούν να είναι τροποποιημένα, ατροποποίητα ή καταχωρημένα. Τα μη-παρακολουθούμενα αρχεία από την άλλη μπορούν να είναι ο,τιδήποτε άλλο. Τα αρχεία αυτά μπορούν να είναι οποιοδήποτε αρχεία στον κατάλογο εργασίας μας τα οποία δεν βρίσκονταν στο τελευταίο στιγμιότυπο και ούτε έχουν καταχωρηθεί ακόμα. Για παράδειγμα, όταν κλωνοποιούμε για πρώτη φορά ένα αποθετήριο, όλα τα αρχεία θα είναι παρακολουθούμενα και ατροποποίητα καθώς μόλις τα ενημερώσαμε και δεν τα έχουμε επεξεργαστεί ακόμα.

Καθώς επεξεργαζόμαστε τα αρχεία, το Git θα τα αναγνωρίζει ως τροποποιημένα καθώς έχουν αλλάξει από την τελευταία φορά που υποβάλλαμε κάποια αρχεία. Τα επόμενα στάδια είναι η καταχώρηση των τροποποιημένων αρχείων και η υποβολή τους, η διαδικασία αυτή θα επαναλαμβάνεται συνέχεια.

Ο κύκλος ζωής της κατάστασης των αρχείων μας.
Figure 8. Ο κύκλος ζωής της κατάστασης των αρχείων μας.

Έλεγχος της κατάστασης των αρχείων μας

Το βασικό εργαλείο που μπορούμε να χρησιμοποιήσουμε ώστε να δούμε την τρέχουσα κατάσταση των αρχείων είναι η εντολή git status. Αν εκτελέσουμε την αυτήν την εντολή αμέσως αφού κλωνοποιήσουμε ένα αποθετήριο, θα δούμε στη γραμμή εντολών το παρακάτω μήνυμα:

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

Το μήνυμα αυτό σημαίνει ότι έχουμε ένα καθαρό κατάλογο εργασίας. Με άλλα λόγια, δεν υπάρχουν τροποποιημένα ή παρακολουθούμενα αρχεία. Επίσης δεν υπάρχουν ούτε μη-παρακολουθούμενα αρχεία αλλιώς το Git θα τα είχε καταγράψει στο παραπάνω μήνυμα. Επίσης, η εντολή αυτή μας ενημερώνει σε ποιον κλάδο βρισκόμαστε καθώς και ότι δεν έχει αποκλίνει από τον αντίστοιχο κλάδο του διακομιστή. Προς το παρόν χρησιμοποιούμε τον κύριο κλάδο, master, ο οποίος είναι και ο προεπιλεγμένος. Θα αναφερθούμε πιο αναλυτικά στους κλάδους στο κεφάλαιο Διακλαδώσεις στο Git.

Έστω ότι έχουμε προσθέσει ένα νέο αρχείο στο έργο μας, ένα απλό αρχείο README. Αν το αρχείο αυτό δεν προυπήρχε και εκτελέσουμε την εντολή git status, θα δούμε το μη-παρακολουθούμενο αρχείο μας ως εξής:

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

Βλέπουμε λοιπόν ότι το αρχείο README είναι μη-παρακολουθούμενο καθώς βρίσκεται κάτω από την κατηγορία Untracked files. Ένα μη-παρακολουθούμενο αρχείο ουσιαστικά σημαίνει ότι το Git βλέπει ένα αρχείο το οποίο δεν υπήρχε στο προηγούμενο στιγμιότυπο (την τελευταία φορά που υποβάλλαμε αρχεία). Το Git δεν θα συμπεριλάβει το αρχείο αυτό στα επόμενα στιγμιότυπα που θα υποβάλλουμε αν δεν το ζητήσουμε ρητά. Αυτό γίνεται ώστε να μην συμπεριλάβουμε κατά λάθος στο έργο μας αρχεία τα οποία δεν θέλαμε, για παράδειγμα δυαδικά αρχεία. Στην περίπτωσή μας, θέλουμε να συμπεριλάβουμε το αρχείο README στο έργο μας οπότε πάμε να ενημερώσουμε το Git ώστε να το παρακολουθεί.

Παρακολούθηση νέων αρχείων

Για να παρακολουθεί το Git ένα καινούριο αρχείο, χρησιμοποιούμε την εντολή git add. Ξεκινάμε την παρακολούθηση του αρχείου REAMDE με την εντολή:

$ git add README

Αν τώρα εκτελέσουμε την εντολή για να δούμε την τρέχουσα κατάσταση του αποθετηρίου, θα δούμε ότι το αρχείο README πλέον παρακολουθείται και έχει τοποθετηθεί στο στάδιο καταχώρισης ώστε να είναι έτοιμο να υποβληθεί:

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

    new file:   README

Το αρχείο πλέον βρίσκεται κάτω από την κατηγορία Changes to be committed που σημαίνει ότι έχει τοποθετηθεί στο στάδιο καταχώρισης. Αν σε αυτό το σημείο κάνουμε υποβολή των αρχείων μας, η έκδοση του αρχείου README που θα αποθηκευτεί στο στιγμιότυπ θα είναι αυτή που υπήρχε όταν εκτελέσαμε την εντολή git add. Προηγουμένως κάναμε κάτι αντίστοιχο, εκτελέσαμε την εντολή git init ακολουθούμενη από git add (files). Με τον τρόπο αυτό ξεκινήσαμε την παρακολούθηση των αρχείων του καταλόγου. Η εντολή git add μπορεί να ακολουθείται είτε από ένα αρχείο είτε από έναν κατάλογο. Αν ακολουθείται από κατάλογο τότε η εντολή θα καταχωρήσει όλα τα αρχεία του συγκεκριμένου καταλόγου αναδρομικά.

Καταχώρηση τροποποιημένων αρχείων

Πάμε λοιπόν να τροποποιήσουμε ένα αρχείο το οποίο παρακολουθείται ήδη. Έστω ότι τροποποιούμε ένα ήδη παρακολουθούμενο αρχείο, το CONTRIBUTING.md, και εκτελούμε την εντολή git status ξανά:

$ 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

Το αρχείο CONTRIBUTING.md βρίσκεται κάτω από την κατηγορία Changed but not staged for commit, που σημαίνει ότι ένα ήδη παρακολουθούμενο αρχείο έχει τροποποιηθεί στον κατάλογο εργασίας, αλλά δεν έχει καταχωρηθεί ακόμα. Για να το καταχωρήσουμε θα πρέπει να εκτελέσουμε την εντολή git add. Η εντολή git add έχει πολλές λειτουργίες: τη χρησιμοποιούμε για να ξεκινήσουμε την παρακολούθηση καινούριων αρχείων, για να καταχωρήσουμε αρχεία αλλά και για άλλες λειτουργίες όπως το να σημειώσουμε αρχεία που προέρχονται από συγκρούσεις συγχώνευσης (merge conflicts) ως επιλυμένα. Μπορούμε να σκεφτούμε την εντολή ως “πρόσθεσε αυτό το περιεχόμενο σε ό,τι υποβάλλεις την επόμενη φορά” αντί για “πρόσθεσε αυτό το αρχείο στο έργο”. Πάμε λοιπόν να εκτελέσουμε την εντολή git add για να καταχωρήσουμε το αρχείο CONTRIBUTING.md και έπειτα να δούμε την τρέχουσα κατάσταση του αποθετηρίου:

$ 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

Και τα δύο αρχεία πλέον είναι καταχωρημένα και θα συμπεριληφθούν στην επόμενη υποβολή στιγμιοτύπου. Στο σημείο αυτό, ας υποθέσουμε ότι θυμόμαστε μια μικρή αλλαγή που θέλουμε να κάνουμε στο αρχείο CONTRIBUTING.md πριν το υποβάλλουμε. Αφού κάνουμε την αλλαγή που θέλουμε, είμαστε έτοιμοι για την υποβολή. Παρόλα αυτά ας εκτελέσουμε git status άλλη μια φορά:

$ 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

Περίεργο ε; Το αρχείο CONTRIBUTING.md αναφέρεται πλέον ως καταχωρημένο αλλά και ως μη καταχωρημένο. Πώς είναι αυτό δυνατόν? Αυτό που συμβαίνει είναι ότι το Git καταχωρεί ένα αρχείο ακριβώς όπως είναι τη στιγμή που εκτελούμε την εντολή git add. Αν υποβάλλουμε το στιγμιότυπο τώρα, η έκδοση του αρχείου CONTRIBUTING.md που υπήρχε όταν εκτελέσαμε την εντολή git add είναι αυτή που θα συμπεριληφθεί στην υποβολή (και όχι η τωρινή έκδοση του αρχείου). Γενικά, αν τροποποιήσουμε ένα αρχείο αφότου έχει εκτελεστεί η εντολή git add, θα πρέπει να την εκτελέσουμε ξανά ώστε να καταχωρήσουμε την τελευταία έκδοση του αρχείου:

$ 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

Σύντομη κατάσταση

Ενώ η εντολή git status μας δίνει αρκετά περιεκτική πληροφορία, είναι επίσης και πολύ μακροσκελής. Στο Git μπορούμε να δούμε και μια πιο σύντομη περιγραφή της κατάστασης του αποθετηρίου. Αν εκτελέσουμε git status -s ή git status --short θα έχουμε ένα πιο απλοποιημένο αποτέλεσμα.

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

Τα καινούργια αρχεία που δεν παρακολουθούνται ακόμα συμβολίζονται με ??, τα καινούρια αρχεία που έχουν καταχωρηθεί με A, τα τροποποιημένα αρχεία με M κ.ο.κ. Το αποτέλεσμα της εντολής περιλαμβάνει δύο σύμβολα για το κάθε αρχείο. Το αριστερό σύμβολο υποδηλώνει ότι το αρχείο έχει καταχωρηθεί και το δεξί ότι έχει τροποποιηθεί. Για παράδειγμα, το αρχείο README είναι τροποιποιημένο στο κατάλογο εργασίας, αλλά δεν έχει καταχωρηθεί ακόμα. Το αρχείο lib/simplegit.rb είναι τροποποιημένο και καταχωρημένο. Το αρχείο Rakefile από την άλλη έχει τροποποιηθεί, καταχωρηθεί, και τροποποιηθεί ξανά που σημαίνει ότι υπάρχουν κάποιες αλλαγές που έχουν καταχωρηθεί και κάποιες που δεν έχουν.

Αγνοώντας αρχεία

Είναι συχνό φαινόμενο να υπάρχει μια κατηγορία αρχείων που δεν θέλουμε να καταχωρηθούν αυτόματα από το Git, αλλά ούτε και να τα βλέπουμε ως μη-παρακολουθούμενα. Συνήθως αυτά είναι αρχεία που δημιουργούνται αυτόματα όπως αρχεία καταγραφής ή αρχεία που δημιουργούνται από τον μεταγλωττιστή. Σε αυτές τις περιπτώσεις μπορούμε να βρούμε το μοτίβο των ονομάτων των αρχείων που δεν χρειαζόμαστε και να τα καταχωρήσουμε στο αρχείο .gitignore. Ας δούμε ένα παράδειγμα αρχείου .gitignore:

$ cat .gitignore
*.[oa]
*~

Η πρώτη γραμμή ενημερώνει το Git ώστε να αγνοεί όλα τα αρχεία που τελειώνουν σε .o ή .a. Η δεύτερη γραμμή ενημερώνει το Git ώστε να αγνοεί όλα τα αρχεία που τελειώνουν με τον χαρακτήρα της ισπανικής περισπωμένης (~), το οποίο χρησιμοποιείται από πολλούς επεξεργαστές κειμένου, όπως ο Emacs, για να δηλώσει τα προσωρινά αρχεία. Μπορούμε επίσης να συμπεριλάβουμε καταλόγους που περιλαμβάνουν αρχεία καταγραφής, προσωρινούς καταλόγους κ.ο.κ. Γενικά είναι καλή ιδέα να ρυθμίσουμε το αρχείο .gitignore νωρίς ώστε να μην υποβάλλουμε κατά λάθος αρχεία που δεν θέλουμε να βρίσκονται στο αποθετήριο.

Οι κανόνες για τα μοτίβα που μπορούμε να δηλώσουμε στο αρχείο .gitignore είναι οι εξής:

  • Οι κενές γραμμές ή οι γραμμές που ξεκινούν με # θα αγνοηθούν.

  • Μπορούμε να χρησιμοποιήσουμε τα κλασικά μοτίβα για ονόματα αρχείων (glob patterns).

  • Μπορούμε να ξεκινήσουμε τα μοτίβα μας με μια κάθετο (/) ώστε να αποφύγουμε την αναδρομικότητα

  • Μπορούμε να τελειώσουμε τα μοτίβα μας με μια κάθετο (/) ώστε να ορίσουμε έναν κατάλογο.

  • Μπορούμε να αντιστρέψουμε ένα μοτίβο χρησιμοποιώντας ένα θαυμαστικό (!) στην αρχή του.

Τα μοτίβα αυτά είναι σαν απλοποιημένες κανονικές εκφράσεις (regular expressions) που χρησιμοποιούν τα λειτουργικά συστήματα. Ένας αστερίσκος (*) αντιστοιχεί σε 0 ή περισσότερους χαρακτήρες. Το [abc] αντιστοιχεί σε οποιονδήποτε χαρακτήρα βρίσκεται μέσα στις αγκύλες. Το σύμβολο του αγγλικού ερωτηματικού (?) αντιστοιχεί σε έναν και μόνο χαρακτήρα. Αν οι αγκύλες περιέχουν 2 χαρακτήρες που μεταξύ τους χωρίζονται με παύλα ([0-9]) τότε αυτή η έκφραση αντιστοιχεί σε όλους τους χαρακτήρες που υπάρχουν μεταξύ των 2 χαρακτήρων (στην περίπτωσή μας, όλοι οι αριθμοί από το 0 μέχρι το 9). Μπορούμε επίσης να χρησιμοποιήσουμε 2 αστερίσκους για να αντιστοιχίσουμε εμφωλευμένους καταλόγους: η έκφραση a/**/z αντιστοιχεί στους καταλόγους a/z, a/b/z, a/b/c/z κ.ο.κ.

Ας δούμε άλλο ένα παράδειγμα ενός αρχείου .gitignore:

# αρχεία .a
*.a

# αλλά να παρακολουθείς το lib.a, παρά το ότι αγνοούμε τα αρχεία .a
!lib.a

# αγνόησε μόνο το αρχείο TODO στον τρέχοντα κατάλογο όχι subdir/TODO
/TODO

# αγνόησε όλα τα αρχεία στον κατάλογο build/
build/

# αγνόησε το doc/notes.txt, αλλά όχι το doc/server/arch.txt
doc/*.txt

# αγνόησε όλα τα .pdf files στον φάκελο doc/
doc/**/*.pdf
Tip

Αν θέλουμε κάποια παραδείγματα για να ξεκινήσουμε, το GitHub διατηρεί μια λίστα με παραδείγματαα αρχείων .gitignore για πολλές γλώσσες προγραμματισμού στη διεύθυνση https://github.com/github/gitignore.

Προβολή των καταχωρημένων και μη-καταχωρημένων αλλαγών

Αν η εντολή git status είναι πολύ αόριστη για εμάς και θέλουμε να δούμε ακριβώς τι έχουμε αλλάξει (και όχι μόνο ποια αρχεία έχουν αλλάξει), μπορούμε να χρησιμοποιήσουμε την εντολή git diff. Θα καλύψουμε την εντολή αυτή πιο αναλυτικά αργότερα, αλλά θα τη χρησιμοποιούμε συχνά για να απαντήσουμε σε 2 ερωτήσεις: Τι έχουμε αλλάξει και δεν έχουμε καταχωρήσει ακόμα; Και επίσης, τι έχουμε καταχωρήσει που είναι έτοιμο για να υποβληθεί; Ενώ η εντολή git status απαντά σε αυτές τις ερωτήσεις πολύ γενικά, απαριθμώντας τα ονόματα των αρχείων, η εντολή git diff θα μας δείξει ακριβώς ποιες γραμμές προστέθηκαν ή αφαιρέθηκαν.

Έστω λοιπόν ότι επεξεργαζόμαστε και καταχωρούμε το αρχείο README και μετά επεξεργαζόμαστε το αρχείο CONTRIBUTING.md χωρίς να το καταχωρήσουμε. Αν τώρα εκτελέσουμε την εντολή git status, θα δούμε κάτι τέτοιο:

$ 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

Για να δούμε τι έχουμε αλλάξει, αλλά δεν έχουμε καταχωρήσει ακόμα, πληκτρολογούμε git diff:

$ 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

Η εντολή αυτή συγκρίνει τον κατάλογο εργασίας μας με ό,τι υπάρχει στην περιοχή καταχώρησης. Το αποτέλεσμά της λοιπόν θα περιλαμβάνει τις αλλαγές που έχουμε κάνει, αλλά δεν έχουμε καταχωρήσει ακόμα.

Αν θέλουμε να δούμε τι έχουμε καταχωρήσει μέχρι τώρα, που θα είναι και μέρος της επόμενης υποβολής, μπορούμε να χρησιμοποιήσουμε την εντολή git diff --staged. Η εντολή αυτή συγκρίνει τις καταχωρημένες αλλαγές με την τελευταία υποβολή:

$ 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

Είναι σημαντικό να σημειώσουμε ότι η εντολή git diff από μόνη της δεν μας εμφανίζει τις αλλαγές που έγιναν από την τελευταία υποβολή, παρά μόνο τις αλλαγές που δεν έχουν ακόμα καταχωρηθεί. Το γεγονός αυτό μπορεί να προκαλεί σύγχυση καθώς για παράδειγμα αν έχουμε καταχωρήσει όλες μας τις αλλαγές, η εντολή git diff δεν θα μας επιστρέψει κάποιο αποτέλεσμα.

Για να καταλάβουμε καλύτερα τη χρήση της εντολής αυτής, ας δούμε άλλο ένα παράδειγμα. Έστω ότι έχουμε ένα αρχείο CONTRIBUTING.md που έχουμε ήδη καταχωρήσει, και έπειτα το έχουμε τροποποιήσει. Μπορούμε να χρησιμοποιήσουμε την εντολή git diff για να δούμε ποιες ακριβώς αλλαγές του αρχείου έχουν καταχωρηθεί και ποιες όχι. Αν λοιπόν το περιβάλλον εργασίας μας είναι κάπως έτσι:

$ 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

Μπορούμε να χρησιμοποιήσουμε την εντολή git diff για να δούμε τι δεν έχει καταχωρηθεί ακόμα

$ 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

καθώς και την εντολή git diff --cached για να δούμε τι έχει καταχωρηθεί μέχρι τώρα (τα --staged και --cached είναι συνώνυμα):

$ 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 μέσω άλλου προγράμματος

Θα συνεχίσουμε να χρησιμοποιούμε την εντολή git diff με διάφορους τρόπους στο βιβλίο. Αν όμως προτιμάμε να βλέπουμε τις διαφορές μεταξύ των αρχείων με κάποιο γραφικό εργαλείο (και όχι μέσα από τη γραμμή εντολών), υπάρχει και άλλος τρόπος. Αν εκτελέσουμε την εντολή git difftool αντί για git diff μπορούμε να δούμε τις διαφορές των αρχείων με προγράμματα όπως τα Araxis, emerge, vimdiff και άλλα. Ας δοκιμάσουμε να εκτελέσουμε την εντολή git difftool --tool-help για να δούμε τι προγράμματα είναι διαθέσιμα για το σύστημά μας.

Υποβολή των αλλαγών

Τώρα που η περιοχή καταχώρησης περιέχει τις αλλαγές που θέλουμε, είμαστε έτοιμοι να τις υποβάλλουμε. Θυμόμαστε ότι όλα τα μη καταχωρημένα αρχεία, δηλαδή όσα αρχεία έχουμε δημιουργήσει ή τροποποιήσει και για τα οποία δεν εκτελέσαμε την εντολή git add, δεν θα συμπεριληφθούν σε αυτήν την υποβολή. Αντί γι' αυτό, θα παραμείνουν ως τροποποιημένα αρχεία στον δίσκο μας. Στην περίπτωσή μας, έστω ότι έχουμε εκτελέσει την εντολή git status και βλέπουμε ότι όλες οι αλλαγές που θέλουμε είναι καταχωρημένες. Είμαστε έτοιμοι πλέον να υποβάλλουμε τις αλλαγές μας. Ο πιο απλός τρόπος για να υποβάλλουμε αλλαγές είναι να πληκτρολογήσουμε git commit:

$ git commit

Με αυτήν την εντολή θα εκκινήσουμε τον προεπιλεγμένο επεξεργαστή κειμένου. Αυτός είναι καθορισμένος από τη μεταβλητή περιβάλλοντος (environment variable) της γραμμής εντολών, $EDITOR, και συνήθως είναι ο vim ή ο emacs. Παρόλα αυτά μπορούμε να χρησιμοποιήσουμε την εντολή git config --global core.editor ώστε να χρησιμοποιήσουμε τον επεξεργαστή κειμένου της αρεσκείας μας, όπως είδαμε στο κεφάλαιο Ξεκινώντας με το Git.

Ο επεξεργαστής κειμένου θα μας εμφανίσει το παρακάτω κείμενο (στο παράδειγμά μας χρησιμοποιούμε το 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
# Changes to be committed:
#	new file:   README
#	modified:   CONTRIBUTING.md
#
~
~
~
".git/COMMIT_EDITMSG" 9L, 283C

Βλέπουμε ότι το προεπιλεγμένο μήνυμα υποβολής περιέχει το τελευταίο αποτέλεσμα της εντολής git status μέσα σε σχόλια (οι γραμμές που ξεκινούν με τη δίεση, #, αποτελούν σχόλια) και μια κενή γραμμή στην αρχή. Μπορούμε να αφαιρέσουμε τα σχόλια αυτά και να γράψουμε το δικό μας μήνυμα υποβολής ή να τα αφήσουμε ως έχουν ώστε να μας βοηθήσουν αργότερα να θυμηθούμε ποια αρχεία υποβάλλουμε. (Για να έχουμε μια ακόμα πιο ρητή υπενθύμιση των αλλαγών που έχουμε κάνει, μπορούμε να χρησιμοποιήσουμε την επιλογή -v στην εντολή git commit. Με τον τρόπο αυτό, θα εισάγουμε τις αλλαγές μας στον επεξεργαστή κειμένου ώστε να δούμε ακριβώς ποιες αλλαγές θα υποβάλλουμε.) Αφού κλείσουμε τον επεξεργαστή κειμένου, το Git θα δημιουργήσει την υποβολή μας με το παραπάνω μήνυμα (τα σχόλια θα αφαιρεθούν).

Εναλλακτικά, μπορούμε να γράψουμε το μήνυμα υποβολής μας μαζί με την εντολή commit, χρησιμοποιώντας την επιλογή -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

Μόλις κάναμε την πρώτη μας υποβολή! Βλέπουμε ότι η υποβολή αυτή μας έχει δώσει κάποιες πληροφορίες: τον κλάδο στον οποίο υποβάλλαμε τις αλλαγές μας (master στην περίπτωσή μας), το SHA-1 άθροισμα ελέγχου (SHA-1 checksum) της υποβολής (463dc4f), πόσα αρχεία αλλάξαμε, καθώς και στατιστικά για το πόσες γραμμές προσθέσαμε και αφαιρέσαμε στην υποβολή αυτή.

Υπενθυμίζουμε ότι η υποβολή αλλαγών καταγράφει το στιγμιότυπο το οποίο είχαμε εκείνη τη στιγμή στην περιοχή καταχώρησης. Ο,τιδήποτε δεν είχαμε καταχωρήσει θα παραμένει εκεί τροποποιημένο, μπορούμε να το υποβάλλουμε αργότερα. Κάθε φορά που πραγματοποιούμε μια υποβολή, καταγράφουμε ένα στιγμιότυπο του έργου μας, το οποίο μπορούμε να χρησιμοποιήσουμε ώστε να επανέλθουμε σε αυτό ή να το συγκρίνουμε με το έργο μας αργότερα.

Παραλείποντας την περιοχή καταχώρησης

Παρόλο που η περιοχή καταχώρησης είναι πολύ χρήσιμη για να διαμορφώνουμε τις υποβολές μας ακριβώς όπως θέλουμε, κάποιες φορές είναι πιο περίπλοκη από όσο χρειαζόμαστε για την εργασία μας. Αν θέλουμε να παραλείψουμε την περιοχή καταχώρησης, το Git παρέχει μια απλή συντόμευση. Προσθέτοντας την επιλογή -a στην εντολή git commit κάνει το Git να καταχωρεί αυτόματα κάθε αρχείο το οποίο παρακολουθείται ήδη πριν κάνουμε την υποβολή. Με αυτόν τον τρόπο μπορούμε να παραλείψουμε την εντολή 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(-)

Παρατηρούμε ότι στην περίπτωση αυτή, δεν έχουμε να εκτελέσουμε την εντολή git add στο αρχείο CONTRIBUTING.md πριν κάνουμε την υποβολή μας.

Αφαιρώντας αρχεία

Για να αφαιρέσουμε ένα αρχείο από το Git, θα πρέπει να το αφαιρέσουμε από τη λίστα με τα παρακολουθούμενα αρχεία (ή πιο σωστά, να το αφαιρέσουμε από την περιοχή καταχώρησης) και έπειτα να το υποβάλλουμε. Αυτό το πραγματοποιούμε με την εντολή git rm, η οποία επίσης θα αφαιρέσει το αρχείο από τον κατάλογο εργασίας μας έτσι ώστε να μην το έχουμε ως μη-παρακολουθούμενο αρχείο.

Αν απλά αφαιρέσουμε το αρχείο από τον κατάλογο εργασίας μας, θα εμφανίζεται κάτω από την κατηγορία Changed but not updated (που ουσιαστικά σημαίνει μη καταχωρημένο) του αποτελέσματος της εντολής 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")

Έπειτα η εντολή git rm θα καταχωρήσει την αφαίρεση του αρχείου:

$ 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

Στην επόμενη υποβολή μας, το αρχείο θα έχει αφαιρεθεί και δεν παρακολουθείται πια. Αν είχαμε τροποποιήσει το αρχείο και είχαμε ήδη προσθέσει στην περιοχή καταχώρησης, θα πρέπει να εξαναγκάσουμε την αφαίρεσή του με την επιλογή -f. Αυτό είναι μια λειτουργία για λόγους ασφάλειας του Git ώστε να αποτρέψει τυχαία αφαίρεση δεδομένων που δεν έχουν ακόμα καταγραφεί σε κάποιο στιγμιότυπο και δεν μπορούν να ανακτηθούν από το Git.

Ένα ακόμα χρήσιμο πράγμα που μπορεί να θέλουμε είναι να κρατήσουμε το αρχείο στον κατάλογο εργασίας μας, αλλά να το αφαιρέσουμε από την περιοχή καταχώρησης. Με άλλα λόγια, μπορεί να θέλουμε να κρατήσουμε το αρχείο στον σκληρό μας δίσκο, αλλά να μην παρακολουθείται από το Git πλέον. Αυτό μπορεί να αποδειχτεί πολύ χρήσιμο αν ξεχάσαμε να προσθέσουμε κάτι στο αρχείο .gitignore και να καταχωρήσαμε κάτι κατά λάθος, όπως για παράδειγμα μεταγλωττισμένα αρχεία. Για να το κάνουμε αυτό, χρησιμοποιούμε την επιλογή --cached:

$ git rm --cached README

Μπορούμε να χρησιμοποιείσουμε την παραπάνω εντολή με αρχεία, καταλόγους και μοτίβα αρχείων. Αυτό σημαίνει ότι μπορούμε να εκτελέσουμε εντολές όπως

$ git rm log/\*.log

Ας σημειωθεί την ανάποδη κάθετο (\) μπροστά από τον αστερίσκο, *. Αυτή είναι απαραίτητη επειδή το Git χρησιμοποιεί τον δικό του τρόπο ώστε να επεκτείνει το όνομα των αρχείων, επιπροσθέτως του τρόπου που χρησιμοποιεί η γραμμή εντολών μας. Η παραπάνω εντολή αφαιρεί όλα τα αρχεία που έχουν την κατάληξη .log στον κατάλογο log/. Επίσης, θα μπορούσαμε να κάνουμε κάτι τέτοιο:

$ git rm \*~

Η εντολή αυτή αφαιρεί όλα τα αρχεία που τελειώνουν με τον χαρακτήρα ~.

Μετακινώντας αρχεία

Σε αντίθεση με άλλα συστήματα ελέγχου έκδοσης, το Git δεν παρακολουθεί τις μετακινήσεις αρχείων από μόνο του. Αν μετονομάσουμε ένα αρχείο στο Git, δεν θα αποθηκευτεί καμιά πληροφορία που να ενημερώνει το Git ότι μετονομάσαμε το αρχείο. Παρόλα αυτά, το Git είναι αρκετά έξυπνο ώστε να καταλάβει κάτι τέτοιο —θα ασχοληθούμε λίγο αργότερα με το πώς παρακολουθείται η μετακίνηση αρχείων.

Έτσι, είναι λίγο περίπλοκο το γεγονός ότι το Git έχει την εντολή mv. Αν θέλουμε να μετονομάσουμε ένα αρχείο στο Git, μπορούμε να το κάνουμε κάπως έτσι

$ git mv file_from file_to

το οποίο θα λειτουργήσει τέλεια. Στην πραγματικότητα, αν εκτελέσουμε κάτι τέτοιο και έπειτα κοιτάξουμε στην κατάσταση του αποθετηρίου, θα δούμε ότι το Git το υπολογίζει ως μετονομασμένο αρχείο:

$ 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

Η εντολή αυτή όμως, είναι ισοδύναμη με το να εκτελέσουμε κάτι τέτοιο:

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

Το Git μπορεί να καταλάβει ότι έμμεσα πρόκειται για μετονομασία. Συνεπώς, δεν έχει σημασία αν μετονομάσουμε ένα αρχείο με αυτόν τον τρόπο ή με την εντολή mv. Η μόνη πραγματική αλλαγή είναι ότι η εντολή mv είναι μία εντολή αντί για τρεις —το χρησιμοποιούμε για ευκολία. Σε κάθε περίπτωση, μπορούμε να χρησιμοποιήσουμε όποιο εργαλείο θέλουμε για να μετονομάσουμε ένα αρχείο, και να λύσουμε το πρόβλημα του add/rm αργότερα, πριν την υποβολή.