-
1. Ξεκινώντας με το Git
-
2. Τα θεμελιώδη στοιχεία του Git
-
3. Διακλαδώσεις στο Git
-
4. Το Git στον διακομιστή
- 4.1 Τα πρωτόκολλα
- 4.2 Εγκατάσταση του Git σε διακομιστή
- 4.3 Δημιουργία δημόσιου κλειδιού SSH
- 4.4 Στήσιμο του διακομιστή
- 4.5 Δαίμονες του Git
- 4.6 Έξυπνο HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Επιλογές φιλοξενίας από τρίτους
- 4.10 Ανακεφαλαίωση
-
5. Κατανεμημένο Git
-
6. GitHub
-
7. Εργαλεία του Git
- 7.1 Επιλογή αναθεώρησης
- 7.2 Διαδραστική εργασία με το στάδιο καταχώρισης
- 7.3 stash και clean
- 7.4 Υπογραφή της δουλειάς μας
- 7.5 Αναζήτηση
- 7.6 Η ιστορία ξαναγράφεται
- 7.7 Απομυθοποίηση της reset
- 7.8 Συγχωνεύσεις για προχωρημένους
- 7.9 Rerere
- 7.10 Αποσφαλμάτωση με το Git
- 7.11 Λειτουργικές υπομονάδες
- 7.12 Δεμάτιασμα δεδομένων
- 7.13 Replace
- 7.14 Αποθήκευση διαπιστευτηρίων
- 7.15 Ανακεφαλαίωση
-
8. Εξατομίκευση του Git
-
9. Το Git και άλλα συστήματα
- 9.1 Το Git ως πελάτης
- 9.2 Μετανάστευση στο Git
- 9.3 Ανακεφαλαίωση
-
10. Εσωτερική λειτουργία του Git
- 10.1 Διοχετεύσεις και πορσελάνες
- 10.2 Αντικείμενα του Git
- 10.3 Αναφορές του Git
- 10.4 Πακετάρισμα αρχείων
- 10.5 Τα refspec
- 10.6 Πρωτόκολλα μεταφοράς
- 10.7 Διατήρηση και ανάκτηση δεδομένων
- 10.8 Μεταβλητές περιβάλλοντος
- 10.9 Ανακεφαλαίωση
-
A1. Appendix A: Το Git σε άλλα περιβάλλοντα
- A1.1 Γραφικές διεπαφές
- A1.2 Το Git στο Visual Studio
- A1.3 Git στο Eclipse
- A1.4 Το Git στο Bash
- A1.5 Το Git στο Zsh
- A1.6 Το Git στο Powershell
- A1.7 Ανακεφαλαίωση
-
A2. Appendix B: Ενσωμάτωση του Git στις εφαρμογές μας
- A2.1 Γραμμή εντολών Git
- A2.2 Libgit2
- A2.3 JGit
-
A3. Appendix C: Εντολές Git
- A3.1 Ρύθμιση και διαμόρφωση
- A3.2 Λήψη και δημιουργία έργων
- A3.3 Βασική λήψη στιγμιοτύπων
- A3.4 Διακλάδωση και συγχώνευση
- A3.5 Κοινή χρήση και ενημέρωση έργων
- A3.6 Επιθεώρηση και σύγκριση
- A3.7 Αποσφαλμάτωση
- A3.8 Επιθέματα
- A3.9 Ηλεκτρονικό ταχυδρομείο
- A3.10 Εξωτερικά Συστήματα
- A3.11 Διοίκηση
- A3.12 Εντολές διοχέτευσης
7.9 Εργαλεία του Git - Rerere
Rerere
Η λειτουργικότητα git rerere
είναι ένα λίγο κρυμμένο χαρακτηριστικό.
Το όνομα σημαίνει “reuse recorded resolution” (“επαναχρησιμοποίηση καταγεγραμμένης επίλυσης”) και όπως υποδηλώνει το όνομα, μας επιτρέπει να ζητήσουμε από το Git να θυμάται πώς έχουμε επιλύσει μια σύγκρουση τμημάτων κώδικα έτσι ώστε την επόμενη φορά που βλέπει την ίδια σύγκρουση, να την επιλύσει αυτόματα.
Υπάρχουν ορισμένα σενάρια στα οποία η λειτουργία αυτή μπορεί να είναι πολύ βολική.
Ένα από τα παραδείγματα που αναφέρονται στην τεκμηρίωση είναι αν θέλουμε να διασφαλίσουμε ότι ένας μακρόβιος θεματικός κλάδος θα συγχωνευθεί χωρίς συγκρούσεις αλλά δεν θέλουμε να έχουμε ένα μάτσο ενδιάμεσων υποβολών συγχώνευσης.
Εφόσον ενεργοποιήσουμε την rerere
μπορούμε να συγχωνεύουμε περιστασιακά, να επιλύσουμε τις συγκρούσεις και στη συνέχεια να αναιρούμε τη συγχώνευση.
Αν το κάνουμε αυτό συνεχώς, τότε η τελική συγχώνευση θα είναι εύκολη επειδή η rerere
θα μπορεί να κάνει τα πάντα για εμάς αυτόματα.
Η ίδια τακτική μπορεί να χρησιμοποιηθεί αν θέλουμε να διατηρήσουμε έναν κλάδο επανατοποθετημένο, ώστε να μην χρειάζεται να ασχολούμαστε με τις ίδιες συγκρούσεις επανατοποθέτησης κάθε φορά που το κάνουμε. Ή αν θέλουμε να πάρουμε έναν κλάδο που συγχωνεύσαμε, στον οποίο επίσης διορθώσουμε μια μερικές συγκρούσεις και στη συνέχεια να αποφασίσαμε να τον επανατοποθετήσουμε σε αλλη βάση —πιθανότατα δεν θα χρειαστεί να επιλύσουμε όλες τις προηγούμενες συγκρούσεις ξανά.
Μια άλλη περίσταση είναι όταν συγχωνεύουμε μερικούς εν εξελίξει θεματικούς κλάδους μαζί σε ένα δοκιμαστικό κεφάλι περιστασιακά, όπως το ίδιο το έργο Git συχνά. Εάν οι δοκιμές αποτύχουν, μπορούμε να αναιρέσουμε τις συγχωνεύσεις και να τις επαναλάβουμε χωρίς τον θεματικό κλάδο εξαιτίας του οποίου απέτυχαν οι δοκιμές, χωρίς να χρειάζεται να ξαναεπιλύσουμε τις συγκρούσεις.
Για να ενεργοποιήσουμε τη λειτουργία rerere
, απλά εκτελέσουμε αυτήν τη ρύθμιση παραμέτρων:
$ git config --global rerere.enabled true
Μπορούμε επίσης να την ενεργοποιήσουμε δημιουργώντας έναν κατάλογο .git/rr-cache
σε ένα συγκεκριμένο αποθετήριο, αλλά η ρύθμιση της παραμέτρου με την config
είναι σαφέστερη και μπορεί να γίνει καθολικά.
Τώρα ας δούμε ένα απλό παράδειγμα, παρόμοιο με το προηγούμενο. Ας υποθέσουμε ότι έχουμε ένα αρχείο που μοιάζει με αυτό:
#! /usr/bin/env ruby
def hello
puts 'hello world'
end
Σε έναν κλάδο αλλάζουμε τη λέξη hello
σε hola
, στη συνέχεια σε έναν άλλο κλάδο αλλάζουμε το world
σε mundo
, ακριβώς όπως πριν.

Όταν συγχωνεύσουμε τους δύο κλάδους, θα πάρουμε σύγκρουση συγχώνευσης:
$ git merge i18n-world
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Recorded preimage for 'hello.rb'
Automatic merge failed; fix conflicts and then commit the result.
Παρατηρούμε τη νέα γραμμή Recorded preimage for FILE
.
Αν δεν υπήρχε, θα φαινόταν ακριβώς όπως μια κανονική σύγκρουση συγχώνευσης.
Σε αυτό το σημείο, η rerere
μπορεί να μας πει μερικά πράγματα.
Κανονικά, θα εκτελούσαμε την git status
σε αυτό το σημείο για να δούμε τι είναι όλες οι συγκρούσεις:
$ git status
# On branch master
# Unmerged paths:
# (use "git reset HEAD <file>..." to unstage)
# (use "git add <file>..." to mark resolution)
#
# both modified: hello.rb
#
Ωστόσο η git rerere
θα μας πει επίσης τι έχει καταγράψει για την κατάσταση προ συγχώνευσης με την git rerere status
:
$ git rerere status
hello.rb
Και η git rerere diff
θα δείξει την τρέχουσα κατάσταση της επίλυσης —με τι ξεκινήσαμε την επίλυση και τι έχουμε μετά την επίλυση.
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,11 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
+<<<<<<< HEAD
puts 'hola world'
->>>>>>>
+=======
+ puts 'hello mundo'
+>>>>>>> i18n-world
end
Επίσης (και αυτό στην πραγματικότητα είναι άσχετο με την rerere
), μπορούμε να χρησιμοποιήσουμε την ls-files -u
για να δούμε τα συγκρουόμενα αρχεία και τις εκδόσεις πρότερες, αριστερές και δεξιές εκδόσεις:
$ git ls-files -u
100644 39804c942a9c1f2c03dc7c5ebcd7f3e3a6b97519 1 hello.rb
100644 a440db6e8d1fd76ad438a49025a9ad9ce746f581 2 hello.rb
100644 54336ba847c3758ab604876419607e9443848474 3 hello.rb
Τώρα μπορούμε να επιλύσουμε τη σύγκρουση (ας πούμε ότι αποφασίζουμε να είναι puts 'hola mundo'
) και μπορούμε να εκτελέσουμε ξανά την εντολή rerere diff
για να δούμε τι θα θυμάται η rerere
:
$ git rerere diff
--- a/hello.rb
+++ b/hello.rb
@@ -1,11 +1,7 @@
#! /usr/bin/env ruby
def hello
-<<<<<<<
- puts 'hello mundo'
-=======
- puts 'hola world'
->>>>>>>
+ puts 'hola mundo'
end
Αυτό ουσιαστικά λέει ότι όταν το Git βλέπει μια σύγκρουση τμήματος κώδικα σε ένα αρχείο hello.rb
που έχει hello mundo
στη μία πλευρά και hola world
στην άλλη, θα την επιλύσει διαλέγοντας hola mundo
.
Τώρα μπορούμε να επισημάνουμε τη σύγκρουση ως επιλυμένη και να την υποβάλλουμε:
$ git add hello.rb
$ git commit
Recorded resolution for 'hello.rb'.
[master 68e16e5] Merge branch 'i18n'
Βλέπουμε ότι αναφέρει Recorded resolution for FILE
.

Τώρα ας αναιρέσουμε αυτήν τη συγχώνευση και στη συνέχεια ας αλλάξουμε τη βάση του θεματικού κλάδου στον κύριο κλάδο.
Μπορούμε να επαναφέρουμε τον κλάδο μας χρησιμοποιώντας την reset
όπως είδαμε στην ενότητα Απομυθοποίηση της reset
.
$ git reset --hard HEAD^
HEAD is now at ad63f15 i18n the hello
Η συγχώνευσή μας αναιρέθηκε. Τώρα ας επαντοποθετήσουμε τον θεματικό κλάδο.
$ git checkout i18n-world
Switched to branch 'i18n-world'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: i18n one word
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging hello.rb
CONFLICT (content): Merge conflict in hello.rb
Resolved 'hello.rb' using previous resolution.
Failed to merge in the changes.
Patch failed at 0001 i18n one word
Τώρα, πήραμε την ίδια σύγκρουση συγχώνευσης όπως αναμέναμε, αλλά επιπλέον υπάρχει η γραμμή Resolved FILE using previous resolution
.
Αν εξετάσουμε το αρχείο, θα δούμε ότι έχει ήδη επιλυθεί, δεν υπάρχουν επισημάνσεις σύγκρουσης συγχώνευσης.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Επίσης, η git diff
θα μας δείξει πώς ξανα-επιλύθηκε αυτόματα:
$ git diff
diff --cc hello.rb
index a440db6,54336ba..0000000
--- a/hello.rb
+++ b/hello.rb
@@@ -1,7 -1,7 +1,7 @@@
#! /usr/bin/env ruby
def hello
- puts 'hola world'
- puts 'hello mundo'
++ puts 'hola mundo'
end

Μπορούμε επίσης να ξαναδημιουργήσουμε την κατάσταση σύγκρουσης του αρχείου με την εντολή checkout
:
$ git checkout --conflict=merge hello.rb
$ cat hello.rb
#! /usr/bin/env ruby
def hello
<<<<<<< ours
puts 'hola world'
=======
puts 'hello mundo'
>>>>>>> theirs
end
Είδαμε ένα παράδειγμα αυτού στην ενότητα Συγχωνεύσεις για προχωρημένους.
Προς το παρόν, όμως, ας την ξαναεπιλύσουμε τρέχοντας την rerere
ξανά:
$ git rerere
Resolved 'hello.rb' using previous resolution.
$ cat hello.rb
#! /usr/bin/env ruby
def hello
puts 'hola mundo'
end
Έχουμε ξαναεπιλύσει το αρχείο αυτόματα χρησιμοποιώντας την αποθηκευμένη επίλυση rerere
.
Τώρα μπορούμε να τρέξουμε add
και να συνεχίσουμε την αλλαγή βάσης για να την ολοκληρώσουμε.
$ git add hello.rb
$ git rebase --continue
Applying: i18n one word
Έτσι, εάν κάνουμε πολλές συγχωνεύσεις ή θέλουμε o θεματικός κλάδος μας να συμβαδίζει με τον κύριο κλάδο μας χωρίς να έχουμε πάμπολλες συγχωνεύσεις, μπορούμε είτε να κάνουμε συχνά αλλαγές βάσης, είτε να ενεργοποιήσουμε την rerere
για να κάνουμε πιο εύκολη τη ζωή μας.