paint-brush
Git Geçmişini Güvenle Yeniden Yazmak: Bir Kılavuzile@omerosenbaum
2,007 okumalar
2,007 okumalar

Git Geçmişini Güvenle Yeniden Yazmak: Bir Kılavuz

ile Omer Rosenbaum18m2023/04/27
Read on Terminal Reader
Read this story w/o Javascript

Çok uzun; Okumak

Git, bir dosya sisteminin anlık görüntülerini zamanında kaydetmek için kullanılan bir sistemdir. Git deposunda üç "durum" veya "ağaç" bulunur: dizin, hazırlama alanı ve çalışma ağacı. Çalışan bir dizin (ektrory), dosya sistemimizde kendisiyle ilişkilendirilmiş bir Git deposu bulunan herhangi bir dizindir.
featured image - Git Geçmişini Güvenle Yeniden Yazmak: Bir Kılavuz
Omer Rosenbaum HackerNoon profile picture

Bir geliştirici olarak her zaman Git ile çalışırsınız.


Hiç şunu söylediğiniz bir noktaya geldiniz mi: "Ah, ben az önce ne yaptım?"

Git'te işler ters gittiğinde birçok mühendis kendini çaresiz hissediyor (kaynak: XKCD)


Bu yazı size tarihi güvenle yeniden yazmanız için gereken araçları verecektir.

Başlamadan Önce Notlar

  1. Ayrıca bu yazının içeriğini kapsayan canlı bir konuşma da yaptım. Bir videoyu tercih ediyorsanız (veya onu okurken izlemek istiyorsanız) — onu bulabilirsiniz Burada .


  2. Git hakkında bir kitap üzerinde çalışıyorum! İlk versiyonları okuyup geri bildirimde bulunmak ister misiniz? Bana bir e-posta gönder: [email protected]

Git'teki Değişiklikleri Kaydetme

Git'te bir şeylerin nasıl geri alınacağını anlamadan önce Git'te değişiklikleri nasıl kaydettiğimizi anlamalısınız. Zaten tüm terimleri biliyorsanız bu kısmı atlamaktan çekinmeyin.


Git'i bir dosya sisteminin anlık görüntülerini zaman içinde kaydeden bir sistem olarak düşünmek çok faydalıdır. Git deposu göz önüne alındığında üç "durum" veya "ağaç" vardır:

Git deposunun üç "ağacı" (kaynak: https://youtu.be/ozA1V00GIT8)


Genellikle kaynak kodumuz üzerinde çalışırken çalışan bir dizinden çalışırız. Çalışan bir dizin (ectory) (veya çalışan ağaç ), dosya sistemimizde kendisiyle ilişkili bir depoya sahip olan herhangi bir dizindir.


Projemizin klasör ve dosyalarının yanı sıra .git adında bir dizin içerir. .git klasörünün içeriğini daha ayrıntılı olarak şurada anlattım: önceki bir gönderi .


Bazı değişiklikler yaptıktan sonra bunları deponuza kaydetmek isteyebilirsiniz. Bir depo (kısacası: repo ), her biri projenin çalışma ağacının geçmiş bir tarihte, ister sizin makinenizde, ister bir başkasının makinesinde nasıl göründüğünün bir arşivi olan bir commit koleksiyonudur.


Bir depo aynı zamanda kod dosyalarımızın dışında HEAD , dallar vb. gibi şeyleri de içerir.


Arada indeks veya hazırlama alanımız var; bu iki terim birbirinin yerine kullanılabilir. Bir şubeyi checkout aldığımızda Git, dizini , çalışma dizinimize en son teslim alınan tüm dosya içerikleriyle ve orijinal olarak teslim alındığında nasıl göründükleri ile doldurur.


git commit kullandığımızda, taahhüt indeksin durumuna göre oluşturulur.


Yani indeks veya hazırlama alanı bir sonraki taahhüt için oyun alanınızdır. Index ile çalışabilir ve istediğiniz her şeyi yapabilirsiniz, ona dosya ekleyebilir, içindekileri kaldırabilirsiniz ve ancak hazır olduğunuzda devam edip depoya bağlanabilirsiniz.


Uygulamalı hale gelme zamanı 🙌🏻


Yeni bir depo başlatmak için git init kullanın. 1.txt adlı dosyaya bir miktar metin yazın:

Yeni bir repo başlatmak ve içindeki ilk dosyayı oluşturmak (kaynak: https://youtu.be/ozA1V00GIT8)


Yukarıda açıklanan üç ağaç durumundan 1.txt şimdi nerede?


Henüz dizine eklenmediğinden çalışma ağacında.

"1.txt" dosyası artık yalnızca çalışma dizininin bir parçası (kaynak: https://youtu.be/ozA1V00GIT8)


Aşamalandırmak , dizine eklemek için git add 1.txt kullanın.

"git add" kullanımı dosyayı artık dizinde de yer alacak şekilde aşamalandırır (kaynak: https://youtu.be/ozA1V00GIT8)


Artık değişikliklerimizi depoya kaydetmek için git commit kullanabiliriz.

"git commit" kullanmak, depoda bir taahhüt nesnesi oluşturur (kaynak: https://youtu.be/ozA1V00GIT8)


Çalışma ağacının tamamını tanımlayan bir ağaca işaretçi içeren yeni bir taahhüt nesnesi oluşturdunuz. Bu durumda kök klasörde yalnızca 1.txt olacaktır. Ağaca yönelik bir işaretçiye ek olarak taahhüt nesnesi, zaman damgaları ve yazar bilgileri gibi meta verileri içerir.


Git'teki nesneler (taahhütler ve ağaçlar gibi) hakkında daha fazla bilgi için, önceki paylaşımıma göz at .


(Evet, “kontrol et”, kelime oyunu amaçlı 😇)


Git ayrıca bize bu taahhüt nesnesinin SHA-1 değerini de söyler. Benim durumumda c49f4ba (biraz yer kazanmak için bunlar SHA-1 değerinin yalnızca ilk 7 karakteridir).


Bu komutu makinenizde çalıştırırsanız, farklı bir yazar olduğunuz için farklı bir SHA-1 değeri elde edersiniz; ayrıca taahhüdü farklı bir zaman damgasında oluşturursunuz.


Repoyu başlattığımızda Git yeni bir dal oluşturur (varsayılan olarak main adında). Ve Git'teki bir dal yalnızca bir işleme yönelik adlandırılmış bir referanstır . Yani varsayılan olarak yalnızca main dalınız var. Birden fazla şubeniz varsa ne olur? Git hangi dalın aktif dal olduğunu nasıl biliyor?


Git'te HEAD adında, (genellikle) bir şubeye işaret eden ve daha sonra bir taahhüde işaret eden başka bir işaretçi vardır. Bu arada, kaputun altında, HEAD sadece bir dosyadır. Bazı öneklerle birlikte şubenin adını içerir.


Depoya daha fazla değişiklik getirmenin zamanı geldi!


Şimdi bir tane daha oluşturmak istiyorum. Şimdi yeni bir dosya oluşturalım ve onu daha önce olduğu gibi dizine ekleyelim:

"2.txt" dosyası, "git add" ile hazırlandıktan sonra çalışma dizininde ve dizinde bulunur (kaynak: https://youtu.be/ozA1V00GIT8)


Şimdi git commit kullanmanın zamanı geldi. Daha da önemlisi git commit iki şey yapar:


İlk olarak, bir taahhüt nesnesi oluşturur, böylece Git'in dahili nesne veritabanında karşılık gelen SHA-1 değerine sahip bir nesne bulunur. Bu yeni taahhüt nesnesi aynı zamanda üst taahhüte de işaret eder. Bu, git commit komutunu yazdığınızda HEAD işaret ettiği taahhüttür.

İlk başta yeni bir işleme nesnesi oluşturuldu; "main" hâlâ önceki işleme işaret ediyor (kaynak: https://youtu.be/ozA1V00GIT8)


İkincisi, git commit aktif dalın işaretçisini hareket ettirir; bizim durumumuzda bu, main olacaktır ve yeni oluşturulan taahhüt nesnesini işaret edecektir.

"git commit" ayrıca aktif dalı yeni oluşturulan taahhüt nesnesine işaret edecek şekilde günceller (kaynak: https://youtu.be/ozA1V00GIT8)


Değişiklikleri Geri Alma

Tarihi yeniden yazmak için, taahhüt ekleme sürecini geri alarak başlayalım. Bunun için süper güçlü bir araç olan git reset komutunu tanıyacağız.

git reset --soft

Yani daha önce attığınız son adım git commit ; bu aslında iki anlama geliyordu: Git bir commit nesnesi yarattı ve main aktif dal olarak taşıdı. Bu adımı geri almak için git reset --soft HEAD~1 komutunu kullanın.


HEAD~1 sözdizimi HEAD öğesinin ilk ebeveynini belirtir. Taahhüt grafiğinde birden fazla taahhütüm varsa, "Taahhüt 2"yi işaret ederek "Taahhüt 3" deyin, bu da "Taahhüt 1"i işaret eder.


Ve HEAD "Taahhüt 3"ü işaret ettiğini söyleyin. HEAD~1 "Taahhüt 2"ye atıfta bulunmak için kullanabilirsiniz ve HEAD~2 , "Taahhüt 1"e atıfta bulunur.


Yani komuta geri dönelim: git reset --soft HEAD~1


Bu komut Git'ten HEAD işaret ettiği şeyi değiştirmesini ister. (Not: Aşağıdaki diyagramlarda “ HEAD işaret ettiği şey” için *HEAD kullanıyorum). Örneğimizde HEAD main öğesini işaret ediyor. Yani Git yalnızca main işaretçisini HEAD~1 olarak değiştirecek. Yani main “Commit 1”i işaret edecektir.


Ancak bu komut indeksin veya çalışma ağacının durumunu etkilemedi . Yani git status kullanırsanız, git commit çalıştırmadan önceki gibi 2.txt aşamalı olduğunu göreceksiniz.

"Ana"yı "Kayıt 1" olarak sıfırlama (kaynak: https://youtu.be/ozA1V00GIT8)


git log? HEAD başlayacak, main ve ardından "Commit 1"e gidecektir. Bunun, "Commit 2"ye artık geçmişimizden erişilemeyeceği anlamına geldiğine dikkat edin.


Bu, "Taahhüt 2"nin taahhüt nesnesinin silindiği anlamına mı geliyor? 🤔


Hayır silinmiyor. Hala Git'in dahili nesne veritabanında bulunuyor.


Şimdi git push kullanarak mevcut geçmişi aktarırsanız Git, uzak sunucuya "Taahhüt 2" göndermez, ancak taahhüt nesnesi deponun yerel kopyasında hala mevcuttur.


Şimdi tekrar taahhütte bulunun ve bu yeni nesneyi orijinal "Taahhüt 2"den ayırmak için "Taahhüt 2.1" taahhüt mesajını kullanın:

Yeni bir taahhüt oluşturma (kaynak: https://youtu.be/ozA1V00GIT8)


“Taahhüt 2” ve “Taahhüt 2.1” neden farklıdır? Aynı taahhüt mesajını kullansak bile ve şunu işaret etseler bile aynı ağaç nesnesi ( 1.txt ve 2.txt oluşan kök klasörün), farklı zamanlarda oluşturuldukları için hala farklı zaman damgalarına sahiptirler.


Yukarıdaki çizimde Git'in dahili nesne veritabanında hala var olduğunu hatırlatmak için “Commit 2”yi tuttum. Hem "Commit 2" hem de "Commit 2.1" artık "Commit 1"i işaret ediyor, ancak yalnızca "Commit 2.1"e HEAD adresinden ulaşılabilir.

Git Sıfırlama --Karışık

Daha da geriye gitmenin ve daha fazlasını geri almanın zamanı geldi. Bu sefer git reset --mixed HEAD~1 kullanın (not: --mixed , git reset için varsayılan anahtardır).


Bu komut git reset --soft HEAD~1 ile aynı şekilde başlar. Bu, main dal olan HEAD şu anda işaret ettiği şeyin işaretçisini alır ve onu HEAD~1 örneğimizde - "Commit 1" olarak ayarlar.

"git reset --mixed"in ilk adımı "git reset --soft" ile aynıdır (kaynak: https://youtu.be/ozA1V00GIT8)


Daha sonra Git daha da ileri giderek dizinde yaptığımız değişiklikleri etkili bir şekilde geri alır. Yani, dizini mevcut HEAD ile eşleşecek şekilde değiştirmek, ilk adımda ayarladıktan sonra yeni HEAD eşleşecek şekilde değiştirmek.


git reset --mixed HEAD~1 çalıştırırsak, bu HEAD HEAD~1 ("Taahhüt 1") olarak ayarlanacağı ve ardından Git'in dizini "Taahhüt 1" durumuyla eşleştireceği anlamına gelir - bu durumda, bu, 2.txt artık dizinin bir parçası olmayacağı anlamına gelir.

"git reset --mixed" işleminin ikinci adımı, dizini yeni "HEAD" ile eşleştirmektir (kaynak: https://youtu.be/ozA1V00GIT8)


Orijinal “Commit 2” durumuyla yeni bir taahhüt oluşturmanın zamanı geldi. Bu sefer 2.txt dosyasını oluşturmadan önce yeniden hazırlamamız gerekiyor:

"Commit 2.2" oluşturuluyor (kaynak: https://youtu.be/ozA1V00GIT8)


Git Sıfırlama --Zor

Devam edin, daha fazlasını geri alın!


Devam edin ve git reset --hard HEAD~1 çalıştırın


Git yine --soft aşamasıyla başlar ve HEAD ( main ) işaret ettiği şeyi HEAD~1 ("Commit 1") olarak ayarlar.

'git reset --hard'ın ilk adımı 'git reset --soft' ile aynıdır (kaynak: https://youtu.be/ozA1V00GIT8)


Şimdiye kadar, çok iyi.


Daha sonra --mixed aşamasına geçerek dizini HEAD ile eşleştirin. Yani Git, 2.txt aşamalandırmasını geri alır.

"git reset --hard"ın ikinci adımı "git reset --mixed" ile aynıdır (kaynak: https://youtu.be/ozA1V00GIT8)


Git'in daha da ileri giderek çalışma dizinini dizin aşamasıyla eşleştirdiği --hard adımının zamanı geldi. Bu durumda, 2.txt da çalışma dizininden kaldırılması anlamına gelir.

"git reset --hard"ın üçüncü adımı, çalışma dizininin durumunu indeksin durumuyla eşleştirir (kaynak: https://youtu.be/ozA1V00GIT8)


(**Not: Bu özel durumda, dosya izlenmez, dolayısıyla dosya sisteminden silinmez; git reset anlamak için gerçekten önemli değildir).


Git'te bir değişiklik yapmak için üç adımınız var. Çalışma dizinini, dizini veya hazırlama alanını değiştirirsiniz ve ardından bu değişikliklerle yeni bir anlık görüntü kaydedersiniz. Bu değişiklikleri geri almak için:


  • git reset --soft kullanırsak commit adımını geri alırız.


  • git reset --mixed kullanırsak, hazırlama adımını da geri alırız.


  • git reset --hard kullanırsak çalışma dizinindeki değişiklikleri geri alırız.

Gerçek Hayat Senaryoları!

Senaryo #1

Yani gerçek hayattaki bir senaryoda, hepimizin Git'i sevdiği gibi, bir dosyaya ( love.txt ) "Git'i seviyorum" yazın. Devam edin, sahneleyin ve bunu da gerçekleştirin:

"Commit 2.3" oluşturuluyor (kaynak: https://youtu.be/ozA1V00GIT8)


Ah, ah!


Aslında bunu yapmanı istemedim.


Aslında senden yapmanı istediğim şey, bunu taahhüt etmeden önce bu dosyaya birkaç aşk sözü daha yazmandı.

Ne yapabilirsin?


Bunun üstesinden gelmenin bir yolu, git reset --mixed HEAD~1 kullanmak, hem işleme hem de hazırlama eylemlerini etkili bir şekilde geri almak olacaktır:

Hazırlama ve işleme adımlarını geri alma (kaynak: https://youtu.be/ozA1V00GIT8)


Yani main nokta yine "Taahhüt 1"dir ve love.txt artık dizinin bir parçası değildir. Ancak dosya çalışma dizininde kalır. Artık devam edip daha fazla içerik ekleyebilirsiniz:

Daha fazla aşk sözleri ekleniyor (kaynak: https://youtu.be/ozA1V00GIT8)


Devam edin, sahneleyin ve dosyanızı kaydedin:

İstenilen durumla yeni kayıt oluşturma (kaynak: https://youtu.be/ozA1V00GIT8)


Aferin 👏🏻


"Taahhüt 2.4"ün "Taahhüt 1"i işaret eden bu net ve güzel geçmişine sahipsiniz.


Artık araç kutumuzda yeni bir aracımız var, git reset 💪🏻

git reset artık araç kutumuzda (kaynak: https://youtu.be/ozA1V00GIT8)


Bu araç süper, süper kullanışlıdır ve onunla neredeyse her şeyi başarabilirsiniz. Her zaman kullanımı en uygun araç olmayabilir, ancak dikkatli kullanırsanız neredeyse her türlü tarihin yeniden yazılması senaryosunu çözebilir.


Yeni başlayanlar için, Git'te geri almak istediğiniz hemen hemen her zaman için yalnızca git reset kullanmanızı öneririm. Kendinizi rahat hissettiğinizde diğer araçlara geçme zamanı gelmiştir.

Senaryo #2

Başka bir durumu ele alalım.


new.txt adında yeni bir dosya oluşturun; sahneleyin ve taahhüt edin:

"New.txt" ve "Commit 3" oluşturma (kaynak: https://youtu.be/ozA1V00GIT8)


Hata. Aslında bu bir hata. Siz main üzerindeydiniz ve ben sizden bu taahhüdü bir özellik dalında oluşturmanızı istedim. Kötüyüm 😇


Bu yazıdan almanızı istediğim en önemli iki araç var. İkincisi git reset . Bunlardan ilki ve çok daha önemlisi, mevcut durumu ve içinde olmak istediğiniz durumu beyaz tahtaya yansıtmaktır .


Bu senaryo için mevcut durum ve istenen durum şöyle görünür:

Senaryo #2: mevcut ve istenen durumlar (kaynak: https://youtu.be/ozA1V00GIT8)


Üç değişiklik fark edeceksiniz:


  1. main nokta mevcut durumda "Commit 3"ü (mavi olanı), ancak istenen durumda "Commit 2.4"ü işaret eder.


  2. feature dalı mevcut durumda mevcut değil ancak mevcut ve istenilen durumda “Commit 3”e işaret ediyor.


  3. HEAD mevcut durumdaki main ve istenen durumdaki feature işaret eder.


Bunu çizebilirseniz ve git reset kullanmayı biliyorsanız bu durumdan kesinlikle kurtulabilirsiniz.


Tekrar ediyorum, en önemli şey nefes almak ve bunu dışarı çıkarmaktır.


Yukarıdaki çizime bakıldığında mevcut durumdan istenilen duruma nasıl geçilir?


Elbette birkaç farklı yolu var ama her senaryo için yalnızca bir seçenek sunacağım. Diğer seçeneklerle de oynamaktan çekinmeyin.


git reset --soft HEAD~1 kullanarak başlayabilirsiniz. Bu, main önceki taahhüt olan "Taahhüt 2.4"e işaret etmesini sağlayacaktır:

'Ana'yı değiştirme; "Taahhüt 3 bulanık çünkü hâlâ orada, ancak ulaşılamıyor (kaynak: https://youtu.be/ozA1V00GIT8)


Mevcut-istenen diyagramına tekrar baktığınızda yeni bir dallanmaya ihtiyacınız olduğunu görebilirsiniz, değil mi? Bunun için git switch -c feature veya git checkout -b feature (aynı şeyi yapan) kullanabilirsiniz:

'Özellik' dalı oluşturma (kaynak: https://youtu.be/ozA1V00GIT8)


Bu komut aynı zamanda HEAD yeni dalı işaret edecek şekilde günceller.


git reset --soft kullandığınız için dizini değiştirmediniz, dolayısıyla şu anda tam olarak taahhüt etmek istediğiniz duruma sahip - ne kadar kullanışlı! Sadece feature dalını taahhüt edebilirsiniz:

'Özellik' dalına bağlılık (kaynak: https://youtu.be/ozA1V00GIT8)


Ve istediğiniz duruma ulaştınız 🎉

Senaryo #3

Bilginizi ek vakalara uygulamaya hazır mısınız?


love.txt dosyasına bazı değişiklikler ekleyin ve ayrıca cool.txt adında yeni bir dosya oluşturun. Onları sahneleyin ve taahhüt edin:

"Commit 4" oluşturuluyor (kaynak: https://youtu.be/ozA1V00GIT8)


Ah, aslında her değişiklikte bir tane olmak üzere iki ayrı taahhüt oluşturmanı istedim 🤦🏻

Bunu kendiniz denemek ister misiniz?


İşleme ve hazırlama adımlarını geri alabilirsiniz:

"git reset --mixed HEAD~1" kullanarak işlemeyi ve hazırlamayı geri alın (kaynak: https://youtu.be/ozA1V00GIT8)


Bu komutun ardından dizin artık bu iki değişikliği içermez ancak her ikisi de hâlâ dosya sisteminizdedir. Yani şimdi, yalnızca love.txt dosyasını hazırlarsanız, bunu ayrı olarak işleyebilir ve ardından aynısını cool.txt için yapabilirsiniz:

Ayrı olarak taahhüt etme (kaynak: https://youtu.be/ozA1V00GIT8)


Güzel 😎

Senaryo #4

Biraz metin içeren yeni bir dosya ( new_file.txt ) oluşturun ve love.txt dosyasına biraz metin ekleyin. Her iki değişikliği de gerçekleştirin ve taahhüt edin:

Yeni bir taahhüt (kaynak: https://youtu.be/ozA1V00GIT8)


Eyvah 🙈🙈


Bu sefer başka bir şubede olmasını istedim, yeni bir şube değil, daha ziyade mevcut bir şube.


Ne yapabilirsin?


Sana bir ipucu vereceğim. Cevap gerçekten kısa ve gerçekten kolaydır. İlk önce ne yapacağız?


Hayır reset . Çiziyoruz. Yapılacak ilk şey bu, çünkü bu her şeyi çok daha kolay hale getirecek. Yani şu anki durumu bu:

"Ana"daki yeni kayıt mavi görünür (kaynak: https://youtu.be/ozA1V00GIT8)


Peki istenilen durum?

"Mavi" taahhüdün başka bir "mevcut" şubede olmasını istiyoruz (kaynak: https://youtu.be/ozA1V00GIT8)


Mevcut durumdan istenilen duruma nasıl ulaşırsınız, en kolayı ne olur?


Bunun bir yolu, daha önce yaptığınız gibi git reset kullanmak olabilir, ancak denemenizi istediğim başka bir yol daha var.


Öncelikle HEAD existing şubeyi işaret edecek şekilde hareket ettirin:

"Mevcut" şubeye geçin (kaynak: https://youtu.be/ozA1V00GIT8)


Sezgisel olarak yapmak istediğiniz şey, mavi taahhütte yapılan değişiklikleri almak ve bu değişiklikleri ("kopyala-yapıştır") existing şubenin üzerine uygulamaktır. Ve Git'in tam da bunun için bir aracı var.


Git'ten bu taahhüt ile ana taahhüdü arasında yapılan değişiklikleri almasını istemek ve bu değişiklikleri yalnızca aktif dalda uygulamak git cherry-pick kullanabilirsiniz. Bu komut, belirtilen revizyonda yapılan değişiklikleri alır ve bunları aktif işleme uygular.


Ayrıca yeni bir taahhüt nesnesi oluşturur ve aktif dalı bu yeni nesneyi işaret edecek şekilde günceller.

"Git Cherry-Pick"i kullanma (kaynak: https://youtu.be/ozA1V00GIT8)


Yukarıdaki örnekte, oluşturulan taahhüdün SHA-1 tanımlayıcısını belirttim, ancak aynı zamanda, değişikliklerini uyguladığımız taahhüt main işaret ettiği taahhüt olduğundan, git cherry-pick main de kullanabilirsiniz.


Ancak bu değişikliklerin main dalda olmasını istemiyoruz. git cherry-pick değişiklikleri yalnızca existing şubeye uyguladı. Bunları main menüden nasıl kaldırabilirsiniz?


Bunun bir yolu main geri switch ve ardından git reset --hard HEAD~1 kullanmak olacaktır:

"Ana" sıfırlanıyor (kaynak: https://youtu.be/ozA1V00GIT8)


Sen yaptın! 💪🏻


git cherry-pick aslında belirtilen taahhüt ile üst öğesi arasındaki farkı hesapladığını ve ardından bunları aktif işleme uyguladığını unutmayın. Bu, bazen bir çelişki yaşayabileceğiniz için Git'in bu değişiklikleri uygulayamayacağı anlamına gelir, ancak bu başka bir yazının konusu.


Ayrıca Git'ten yalnızca bir şubenin referans verdiği taahhütleri değil, herhangi bir taahhütte yapılan değişiklikleri cherry-pick isteyebileceğinizi unutmayın.


Yeni bir araç edindik, bu nedenle git reset ve git cherry-pick de elimizde bulunduruyoruz.

Senaryo #5

Tamam, başka bir gün, başka bir repo, başka bir sorun.


Bir taahhüt oluşturun:

Başka bir işlem (kaynak: https://youtu.be/ozA1V00GIT8)


Ve uzak sunucuya push :

(kaynak: https://youtu.be/ozA1V00GIT8)


Ah, ah 😓…


Az önce bir şey fark ettim. Orada bir yazım hatası var. This is more tezt This is more text tezt yazdım. Hay aksi. Peki şimdi büyük sorun ne? ed'e push , bu da başka birisinin bu değişiklikleri zaten pull olabileceği anlamına geliyor.


Eğer bu değişiklikleri git reset kullanarak geçersiz kılarsam, şimdiye kadar yaptığımız gibi, farklı geçmişlerimiz olacak ve kıyamet kopabilir. Reponun kendi kopyasını, push kadar istediğiniz kadar yeniden yazabilirsiniz.


Değişikliği bir kez push , eğer tarihi yeniden yazacaksanız, bu değişiklikleri başka kimsenin getirmediğinden emin olmanız gerekir.


Alternatif olarak git revert adlı başka bir aracı kullanabilirsiniz. Bu komut, sağladığınız taahhüdü alır ve tıpkı git cherry-pick gibi, üst taahhüdünden Farkı hesaplar, ancak bu sefer ters değişiklikleri hesaplar.


Dolayısıyla, belirtilen işleme bir satır eklediyseniz, bunun tersi satırı siler ve bunun tersi de geçerlidir.

Değişiklikleri geri almak için "git revert"ü kullanma (kaynak: https://youtu.be/ozA1V00GIT8)


git revert yeni bir taahhüt nesnesi yarattı; bu, onun geçmişe bir ek olduğu anlamına gelir. git revert kullanarak geçmişi yeniden yazmadınız. Geçmişteki hatanızı kabul ettiniz ve bu taahhüt, bir hata yaptığınızın ve şimdi onu düzelttiğinizin kabulüdür.


Bazıları bunun daha olgun bir yol olduğunu söyleyebilir. Bazıları, önceki taahhüdü yeniden yazmak için git reset kullandığınızda alacağınız kadar temiz bir geçmiş olmadığını söyleyebilir. Ancak bu, tarihin yeniden yazılmasını önlemenin bir yoludur.


Artık yazım hatasını düzeltebilir ve tekrar işlem yapabilirsiniz:

Değişiklikleri yeniden yapma (kaynak: https://youtu.be/ozA1V00GIT8)


Araç kutunuz artık yeni ve parlak bir araçla dolu, revert :

Araç kutumuz (kaynak: https://youtu.be/ozA1V00GIT8)


Senaryo #6

Biraz iş yapın, biraz kod yazın ve onu love.txt dosyasına ekleyin. Bu değişikliği gerçekleştirin ve taahhüt edin:

Başka bir işlem (kaynak: https://youtu.be/ozA1V00GIT8)


Makinemde de aynısını yaptım ve klavyemdeki Up ok tuşunu kullanarak önceki komutlara geri döndüm ve ardından Enter tuşuna bastım ve… Vay be.


Hay aksi.

Az önce 'git reset -- hard' mı yaptım? (kaynak: https://youtu.be/ozA1V00GIT8)


Az önce git reset --hard kullandım mı? 😨


Aslında ne oldu? Git işaretçiyi HEAD~1 konumuna taşıdı, bu nedenle tüm değerli çalışmalarımla birlikte son işleme mevcut geçmişten ulaşılamıyor. Git ayrıca hazırlama alanındaki tüm değişiklikleri kaldırdı ve ardından çalışma dizinini hazırlama alanının durumuyla eşleştirdi.


Yani, her şey işimin gittiği bu durumla eşleşiyor.


Çılgınlık zamanı. Çıldırıyorum.

Ama gerçekten korkmak için bir neden var mı? Pek değil… Biz rahat insanlarız. Biz ne yaptık? Peki, sezgisel olarak taahhüt gerçekten bitti mi? Hayır neden olmasın? Hala Git'in dahili veritabanında mevcut.


Bunun nerede olduğunu bilseydim, bu taahhüdü tanımlayan SHA-1 değerini bilirdim ve onu geri yükleyebilirdik. Hatta geri alma işlemini geri alabilir ve bu işleme geri reset .


Yani burada gerçekten ihtiyacım olan tek şey "silinmiş" taahhüdün SHA-1'idir.


Peki soru şu; onu nasıl bulacağım? git log faydalı olur mu?


Aslında değil. git log HEAD gider, bu da main işaret eder, bu da aradığımız taahhüdün ana taahhüdünü gösterir. Daha sonra git log , değerli çalışmamla ilgili taahhüdü içermeyen ana zincir boyunca geriye doğru iz sürecektir.

"git log" bu durumda yardımcı olmuyor (kaynak: https://youtu.be/ozA1V00GIT8)


Neyse ki Git'i yaratan çok akıllı insanlar bizim için bir yedekleme planı da oluşturdular ve buna reflog deniyor.


Git ile çalışırken, git reset kullanarak yapabileceğiniz HEAD öğesinin yanı sıra git switch veya git checkout gibi diğer komutları da değiştirdiğinizde Git, reflog dosyasına bir giriş ekler.


"git reflog" bize "HEAD"in nerede olduğunu gösterir (kaynak: https://youtu.be/ozA1V00GIT8)


Taahhüdümüzü bulduk! 0fb929e ile başlayandır.


Onunla aynı zamanda "takma adı" HEAD@{1} ile de bağlantı kurabiliriz. Git'in, HEAD öğesinin ilk ebeveynine ulaşmak için HEAD~1 kullanması ve HEAD öğesinin ikinci ebeveynine başvurmak için HEAD~2 kullanması gibi, Git, HEAD öğesinin ilk reflog ebeveynine atıfta bulunmak için HEAD@{1} öğesini kullanır, HEAD önceki adımda işaret ettiği yer.


Ayrıca git rev-parse bize değerini göstermesini de isteyebiliriz:

(kaynak: https://youtu.be/ozA1V00GIT8)


reflog görüntülemenin başka bir yolu da git log -g kullanmaktır; bu, git log gerçekten reflog dikkate almasını ister:

"git log -g" çıktısı (kaynak: https://youtu.be/ozA1V00GIT8)


Yukarıda reflog HEAD gibi main işaret ettiğini, yani "Commit 2"yi işaret ettiğini görüyoruz. Ancak reflog bu girişin ebeveyni "Taahhüt 3" e işaret ediyor.


Yani "Taahhüt 3"e geri dönmek için git reset --hard HEAD@{1} (veya "Taahhüt 3"ün SHA-1 değerini) kullanabilirsiniz:

(kaynak: https://youtu.be/ozA1V00GIT8)


Ve şimdi, git log yaparsak:

Tarihimiz geri döndü!!! (kaynak: https://youtu.be/ozA1V00GIT8)


Günü kurtardık! 🎉👏🏻


Bu komutu tekrar kullanırsam ne olur? Ve git commit --reset HEAD@{1} çalıştırdınız mı? Git, HEAD HEAD son reset önce işaret ettiği yere ayarlayacak, yani "Taahhüt 2" anlamına gelecektir. Bütün gün devam edebiliriz:

(kaynak: https://youtu.be/ozA1V00GIT8)


Şimdi araç kutumuza baktığımızda Git'te işlerin ters gittiği birçok durumu çözmenize yardımcı olabilecek araçlarla dolu olduğunu görüyoruz:

Araç kutumuz oldukça kapsamlıdır! (kaynak: https://youtu.be/ozA1V00GIT8)


Bu araçlarla artık Git'in nasıl çalıştığını daha iyi anlayacaksınız. Geçmişi özel olarak yeniden yazmanıza izin verecek daha fazla araç var, git rebase ), ancak bu yazıda zaten çok şey öğrendiniz. Gelecek yazılarda git rebase de değineceğim.


Bu araç kutusunda listelenen beş araçtan bile daha önemli olan en önemli araç, mevcut durum ile arzu edilen durumu beyaz tahtaya yansıtmaktır. Bana güvenin, bu her durumu daha az göz korkutucu hale getirecek ve çözümü daha net hale getirecek.

Git Hakkında Daha Fazla Bilgi Edinin

Ayrıca bu yazının içeriğini kapsayan canlı bir konuşma da yaptım. Bir videoyu tercih ediyorsanız (veya onu okurken izlemek istiyorsanız) — onu bulabilirsiniz .


Genel olarak, YouTube kanalım Git'in ve içindekilerin birçok yönünü kapsar; hoş geldiniz buna bir bak (kelime oyunu amaçlandı 😇)

yazar hakkında

Ömer Rosenbaum CTO'su ve Kurucu Ortağıdır. Yüzmek geliştiricilerin ve ekiplerinin kod tabanları hakkındaki bilgileri güncel dahili belgelerle yönetmelerine yardımcı olan bir geliştirme aracıdır. Ömer, Check Point Security Academy'nin kurucusudur ve yetenekli profesyonelleri teknoloji alanında kariyer geliştirmeleri için eğiten bir eğitim kuruluşu olan ITC'de Siber Güvenlik Lideri olarak görev yapmıştır.


Ömer, Tel Aviv Üniversitesi'nden Dilbilim alanında yüksek lisans derecesine sahiptir ve Kısa YouTube Kanalı .


İlk kez burada yayınlandı