6 puan yazan GN⁺ 2024-05-27 | 1 yorum | WhatsApp'ta paylaş
  • Git’te sık takılınan işlemleri commit oluşturma, branch değiştirme, değişiklik karşılaştırma, uzak depo eşitleme ve değişiklikleri geri alma komutları üzerinden hızlıca bulunabilecek şekilde düzenleyen bir PDF
  • Yerel iş akışı, stage öncesi ve sonrası durumu kontrol edip commit oluşturmak için git status, git add, git commit, git diff etrafında şekilleniyor
  • Branch işlemleri, oluşturma·geçiş·birleştirme·yeniden tabanlama için git switch, git checkout, git branch, git merge, git rebase, git cherry-pick kullanıyor
  • Geçmişi inceleme ve kurtarma için git log, git blame, git show, git reflog, git reset, git restore yer alıyor; branch’ler, tag’ler, HEAD ve uzak branch’ler de commit referansı olarak kullanılabiliyor
  • Uzak depo işlemleri, değişiklikleri alma ve gönderme sürecini git remote add, git fetch, git pull, git push, git push --force-with-lease, git push --tags ile ele alıyor

Depoyu başlatma ve mevcut durumu kontrol etme

  • Yeni depo başlatma:
    • git init
  • Mevcut bir depoyu kopyalama:
    • git clone $URL
  • Geçerli konumu ve durumu kontrol etme:
    • git status

Commit hazırlama ve oluşturma

  • Takip edilmeyen dosya ekleme:
    • git add $FILE
  • Tüm takip edilmeyen dosyaları ve stage edilmemiş değişiklikleri ekleme:
    • git add .
  • Bir dosyadaki değişikliklerin yalnızca bir kısmını seçerek stage etme:
    • git add -p
  • Dosya silme veya taşıma:
    • git rm $FILE
    • git mv $OLD $NEW
  • Dosyayı silmeden Git takibinden çıkarma:
    • git rm --cached $FILE
  • Tüm stage işlemlerini iptal etme:
    • git reset HEAD
  • Commit oluşturma:
    • git commit
    • Mesajı yazmak için metin düzenleyiciyi açar
  • Mesajı doğrudan belirterek commit oluşturma:
    • git commit -m 'message'
  • Stage edilmemiş değişiklikleri de dahil ederek mesajla birlikte commit oluşturma:
    • git commit -am 'message'

Branch değiştirme ve yönetimi

  • Branch değiştirme:
    • git checkout $NAME
    • git switch $NAME
  • Branch oluşturma:
    • git checkout -b $NAME
    • git switch -c $NAME
  • Branch listesini görüntüleme:
    • git branch
  • Branch’leri en son commit’e göre sıralama:
    • git branch --sort=-committerdate
  • Branch silme:
    • git branch -d $NAME
  • Branch’i zorla silme:
    • git branch -D $NAME

Geçmişi inceleme ve kod takibi

  • Bir branch’in geçmişini görüntüleme:
    • git log main
  • İki branch arasındaki ilişkiyi grafik olarak görüntüleme:
    • git log --graph a b
  • Tek satırlık log görüntüleme:
    • git log --oneline
  • Dosyadaki her satırı en son kimin değiştirdiğini görme:
    • git blame $FILENAME
  • Dosyayı değiştiren tüm commit’leri görüntüleme:
    • git log $FILENAME
  • Belirli bir metni ekleyen veya kaldıran commit’leri bulma:
    • git log -S banana

Değişiklikleri karşılaştırma

  • Bir commit ile ebeveyn commit’i arasındaki farkı görüntüleme:
    • git show $COMMIT_ID
  • Bir merge commit ile birleştirilen ebeveynleri arasındaki farkı görüntüleme:
    • git show --remerge-diff $COMMIT_ID
  • Diff özetini görüntüleme:
    • git diff $COMMIT_ID --stat
    • git show $COMMIT_ID --stat
  • İki commit’i karşılaştırma:
    • git diff $COMMIT_ID $COMMIT_ID
  • Yalnızca belirli bir dosyayı commit ile karşılaştırma:
    • git diff $COMMIT_ID $FILENAME
  • Stage edilmiş ve stage edilmemiş tüm değişiklikleri karşılaştırma:
    • git diff HEAD
  • Yalnızca stage edilmiş değişiklikleri karşılaştırma:
    • git diff --staged
  • Yalnızca stage edilmemiş değişiklikleri karşılaştırma:
    • git diff

Yapılandırma dosyaları ve seçenekler

  • Yerel Git yapılandırma dosyası:
    • .git/config
  • Genel Git yapılandırma dosyası:
    • ~/.gitconfig
  • Yoksayılacak dosya listesi:
    • .gitignore
  • Yapılandırma seçeneği belirleme:
    • git config user.name 'Julia'
  • Genel seçenek belirleme:
    • git config --global ...
  • Alias ekleme:
    • git config alias.st status
  • Kullanılabilir yapılandırma seçeneklerini görüntüleme:
    • man git-config

Geçmişi düzenleme ve dosya geri yükleme

  • En son commit’i geri alma, çalışma dizinini olduğu gibi koruma:
    • git reset HEAD^
  • Başarısız bir rebase’i geri alma:
    • git reflog BRANCHNAME
    • git reset --hard $COMMIT_ID
  • Son 5 commit’i tek commit’te birleştirme:
    • git rebase -i HEAD^^^^^^
    • Birleştirilecek commit’lerde pick yerine fixup yazılır
  • Başka bir branch veya commit’ten dosya sürümünü alma:
    • git checkout $COMMIT_ID $FILE
    • git restore $FILE --source $COMMIT_ID
  • Commit mesajını değiştirme veya unutulan dosyaları ekleme:
    • git commit --amend

Branch’leri birleştirme

  • Geçerli branch’i başka bir branch üzerinden güncelleyen fast-forward merge:
    • git switch main
    • git merge banana
  • Bir commit’i başka bir branch’e kopyalama:
    • git cherry-pick $COMMIT_ID
  • Ayrışmış branch’leri rebase ile birleştirme:
    • git switch banana
    • git rebase main
  • Ayrışmış branch’leri merge ile birleştirme:
    • git switch main
    • git merge banana
    • git commit
  • Ayrışmış branch’leri squash merge ile birleştirme:
    • git switch main
    • git merge --squash banana
    • git commit

Uzak depo ve eşitleme

  • Uzak depo ekleme:
    • git remote add $NAME $URL
  • main branch’ini origin uzak deposuna push etme:
    • git push origin main
  • İlk kez push edilen branch’i origine gönderip takip branch’ini ayarlama:
    • git push -u origin $NAME
  • Geçerli branch’i uzak takip branch’ine push etme:
    • git push
  • Zorla push etme:
    • git push --force-with-lease
  • Tag’leri push etme:
    • git push --tags
  • Değişiklikleri alma, yerel branch’leri değiştirmeme:
    • git fetch origin main
  • Tüm branch’leri fetch etme:
    • git fetch --all
  • Fetch sonrası geçerli branch üzerinde rebase yapma:
    • git pull --rebase
  • Fetch sonrası geçerli branch üzerinde merge yapma:
    • git pull origin main
    • git pull

Commit’i işaret etme yöntemleri

  • $COMMIT_ID yerine çeşitli referanslar kullanılabilir:
    • Branch: main
    • Tag: v0.1
    • Commit ID: 3e887ab
    • Uzak branch: origin/main
    • Geçerli commit: HEAD
    • 3 commit önceki durum: HEAD^^^
    • 3 commit önceki durum: HEAD~3

Değişiklikleri atma

  • Tek bir dosyadaki stage edilmiş ve stage edilmemiş tüm değişiklikleri silme:
    • git checkout HEAD $FILE
  • Tek bir dosyadaki stage edilmemiş değişiklikleri silme:
    • git checkout $FILE
  • Tüm stage edilmiş ve stage edilmemiş değişiklikleri silme:
    • git reset --hard
  • Stage edilmiş ve stage edilmemiş değişiklikleri stash’e alma:
    • git stash
  • Takip edilmeyen dosyaları silme:
    • git clean

1 yorum

 
GN⁺ 2024-05-27
Hacker News görüşleri
  • Birkaç gizli cevher gibi komut var: git diff --staged son commit ile şu anda stage edilen içerik arasındaki farkı gösteriyor; bu yüzden dosya ya da hunk’ları ince ayarla eklerken yalnızca amaçlanan içeriğin girdiğini doğrulamak için çok iyi
    git log <file> yalnızca o dosyanın değiştirildiği commit’leri gösteriyor; böylece tüm git log çıktısını kurcalama ihtiyacı azalıyor ve özellikle sık değişmeyen dosyalarda faydalı oluyor
    git add --patch kullanırken Git’in böldüğü hunk’lardan daha ayrıntılı seçim yapmak isterseniz e seçeneğini deneyin. Tek tek satırları nasıl dahil edip hariç tutacağınızı yönlendiriyor, yani ezberlemeniz gerekmiyor

    • git diff --staged komutunun git diff --cached için bir takma ad olduğunu ancak şimdi öğrendim. Yıllardır cached kullanıyordum ama staged kesinlikle daha sezgisel. Yine de bu kas hafızasını silebilir miyim emin değilim
    • Bu tür komutlar için bolca takma ad tanımlamak epey zaman kazandırıyor ve işi daha düzenli yürütmenin önündeki eşiği de düşürüyor
      İlgileniyorsanız bakabilir veya takma ad önerebilirsiniz: https://gitlab.com/Falimonda/gitrc
    • git config --global commit.verbose true ayarlanırsa Git, commit mesajı düzenleyicisindeki yorum alanına stage edilmiş diff’i otomatik olarak ekliyor
  • Listede yok ama sevdiğim komutlardan biri git log -LstartLine,endLine:fileName
    Genişletilmiş bir git blame gibi çalışıyor; belirtilen satırların zaman içinde nasıl değiştiğini ve bunları kimin değiştirdiğini gösteriyor. Satır numaraları değişse veya dosya taşınsa bile takibi sürdürüyor
    “Bunu kim, ne zaman, neden böyle yaptı?” ya da “Bu ne zamandan beri böyle?” gibi sorulara cevap veriyor

  • Phil Karlton’ın “Bilgisayar biliminde zor olan yalnızca iki şey vardır: cache invalidation ve isimlendirme.” sözü aklıma geldi
    Bu açıdan bakınca Git komut adının blame olması epey tuhaf gelmişti; bunu sadece ben düşünmüyormuşum
    What does 'git blame' do? https://stackoverflow.com/questions/31203001/what-does-git-blame-do
    Blame someone else for your bad code https://news.ycombinator.com/item?id=27963868
    Git blame should be called git credit https://dev.to/damcosset/git-blame-should-be-called-git-credit-27h5
    Does Git Blame sound too negative? https://www.reddit.com/r/ProgrammerHumor/comments/r5lzyo/does_git_blame_sound_too_negative_just_look_up/

    • Aracın adının git olduğunu düşününce, blame markaya uygun bir isim gibi duruyor
    • Katılıyorum. Ben ayarlarımda blame adını who olarak değiştirdim. Aslında koyu bir Vim kullanıcısı olduğum için sadece w kullanıyorum
  • Git’i öğrenme biçimini beğendim. İlk başta üçüncü taraf bir Git GUI’si olan Sourcetree ile başladım; kullanması ve anlaması çok kolaydı
    Sonra git guiya geçtim ama bu aşama atlanabilir. Ardından UI açmak zahmetli gelmeye başladı ve terminal komutlarını öğrendim
    Git’e yeni başlayanlara bunu öneririm ama sonuçta bu yalnızca benim n=1 deneyimim

    • Git hakkında bildiğim tek şey clone, pull, commit, push ve şimdiye kadar bu yetti. Git bu kadar basit de olabilir. Elbette ihtiyaç olursa daha karmaşık kullanım biçimleri de öğrenilebilir
    • Terminal komutlarına geri dönmek istemiyorum. Git deposu ve iş akışları görselleştirildiğinde çok daha iyi anlaşılıyor; bu yüzden Git aslında neredeyse GUI ile kullanılmayı gerektiren bir araç
      Magit kullanmaya başladığım anda Git’i anlamaya başladım
    • Ben Sourcetree’den Fork’a geçtim. Çok benziyor ama performansı çok daha iyi ve arayüzü daha akıcı. Tabii son birkaç yılda Sourcetree düzelmediyse
    • Benzer bir yol izledim ama GitKraken ve Sublime Merge kullandım; karmaşık işleri bile kolaylaştırdığı için Sublime Merge bende kaldı
      Sublime Merge hakkında söyleyebileceğim tek şey övgü
  • Git’in gereksiz yere karmaşık olmasının tarihsel nedenleri olup olmadığını merak ediyorum
    Bu kopya kağıdını görünce bu karmaşıklığı daha çok hissediyorum

    • Evet. Bunun nedeni Git’in, Linus Torvalds’ın Linux çekirdeği geliştirmesini mümkün kılmak ve ilerletmek için yapılmış bir araç olması
      Bu kadar yaygınlaşmış olması “mutlu bir kaza” da olabilir, talihsizlik de. GitHub’ın “ücretsiz Git barındırma” ile Git’i yaygınlaştırmadaki payı büyük ama Git’in birçok proje için ideal sürüm kontrol sistemi olduğunu düşünmüyorum
      Linus ve Linux için yapıldığı için, terminoloji ve iş akışı diğer sıradan sürüm kontrol sistemlerine göre ters hissettirebiliyor. Pull Request adı da, Linux geliştirmede Linus’un ya da bakımcının değişiklikleri çekirdek ağacına çekmesinden geliyor. Diğer sistemlerde buna genelde Merge Request deniyor; değişikliklerin nereden geldiğinden bağımsız olarak ağaca birleştirilmesini anlattığı için o ad çok daha mantıklı
      Git, devasa kod tabanlarını hızlı işleyebilen neredeyse tek açık kaynak dağıtık sürüm kontrol sistemi idi ve bu yüzden büyük şirketlerde de ataleti arttı
      Kişisel projelerde Mercurial’i çok daha fazla tercih ediyor ve gerçekten kullanıyorum ama Android AOSP gibi büyük kod tabanlarında Hg kullanmayı denerseniz ciddi şekilde tekliyor. Mercurial’ın kullanıcı arayüzü ve komut sistemi daha iyi, ayrıca değişiklik ağacını görmek için anında bir web sunucusu açma özelliği de var; ancak Python ile yazıldığı için performans ve ölçeklenebilirlik açısından ideal değil
    • Karmaşıklığın bir kısmı, ilk sürümlerde yeni alt komut eklemenin maliyetinin epey yüksek olmasından kaynaklanıyordu. Sonuç olarak git checkout gibi mevcut alt komutlara sürekli yeni işlevler yüklendi ve bu da kullanıcı deneyimini daha kafa karıştırıcı hale getirdi
      Modern Git’te yeni alt komut ekleme maliyeti azaldı ve git switch gibi daha spesifik komutlar eklenmeye başlandı
    • Çoğu iş akışında log, add, commit, pull, push gibi birkaç Git komutunu bilmek yeterli bence. GUI araçları da var
      Dürüst olmak gerekirse, tipik kullanımda Git’in o kadar da karmaşık olduğunu düşünmüyorum. Sadece gerektiğinde kullanılabilecek çok sayıda güçlü özelliği var
    • Git gereksiz yere karmaşık değil. Git’in desteklemek için tasarlandığı iş akışının kendisi olağanüstü derecede karmaşıktı ve hedef kullanıcıları olan çekirdek geliştiricileri çok teknik kişilerdi, bu yüzden karmaşıklık büyük bir sorun değildi
      Çekirdek geliştiricileri merkezi olmayan bir şekilde birbirleriyle iletişim kurmak ve birbirlerinin işi üzerine tekrar çalışmak zorundaydı. 15.000 kişinin kod yazdığı bir projede nasıl çalışılır? Git bu amaç için yapıldı
      Tasarlandığı iş akışını desteklemek için gerektiği kadar karmaşık. Daha basit bir araç yapmak kolaydır ama o zaman Linux çekirdeği geliştirme gibi karmaşık iş akışlarını destekleyemez. Bu yüzden gereksiz yere karmaşık değil ama daha basit kullanım senaryoları için gerekenden karmaşık olduğu doğru
      Daha az karmaşık bir frontend istiyorsanız, Git’i daha kolay kullanmanızı sağlayan çok araç var. Tam zamanlı bir yazılım geliştiricisi değilseniz Git’i doğrudan kullanmanızı önermem. Ama tam zamanlı geliştiriciyseniz, iç kavramları anlamaya zaman ayırmaya değer ve bir kez anladığınızda Git yaptığı işe göre oldukça zarif
      Bir yazılım geliştiricisini Git biliyor mu diye elemem ama bu tür temel sistemlerin nasıl çalıştığını kendi başına çözmek size dopamin vermiyorsa bu alan size göre olmayabilir. Yine de sorun değil; herkes için uygun olan ve olmayan şeyler var
      Git dallanıp ilerlemeyi öğrenmek için https://learngitbranching.js.org tavsiye ederim. Tabii https://xkcd.com/1597/ de geçerli
    • İyi UI tasarımı başlı başına ayrı bir uzmanlık ve ek çaba gerektiriyor, bu yüzden çoğu zaman doğrudan göz ardı ediliyor
  • git add -p komutunu bilmiyordum, gerçekten çok faydalı
    -p, --patch, indeks ile çalışma ağacı arasındaki patch hunk’larını etkileşimli olarak seçip indekse eklemenizi sağlar. Değişiklikleri indekse eklemeden önce farkları gözden geçirme fırsatı verir

    • Mümkün olduğunda mevcut çalışmanın hunk’larını doğrudan seçip tutarlı commit’ler halinde topluyorum. Bu, yaptığım şeyi zihnimde yeniden düzenlememe yardımcı oluyor ve birine açıklamam gerektiğinde commit akışını takip ederek anlatabiliyorum
  • Buraya eklemek istediğim şey, git commit --fixup $COMMIT_ID ile git rebase -i upstream/master --autosquash kombinasyonu
    Son dönemdeki iş akışımın vazgeçilmez bir parçası oldu. Julia’nın örneğinde önceki 5 commit’i rebase etmek için HEAD^^^^^ kullanılıyor ama ben yakın zamana kadar HEAD~5 kullanıyordum. Fakat artık upstream HEAD’e kadar olan tüm commit’leri doğrudan rebase edebileceğimi öğrendim

    • git commit --fixup $COMMIT_ID’i hemen kullanmaya başlamalıyım. Ben hep “oops GET users/me” gibi küçük düzeltme commit’leri oluşturup bir sonraki etkileşimli rebase sırasında bunları elle taşıyıp fixup yapıyordum ama bu yöntem çok daha iyi
    • Bunu daha yeni öğrendim ama Gerrit’te yığılı patch’ler ile çalışırken çok iyi oluyor
  • “Son 5 commit’i tek bir commit’te birleştir: git rebase -i HEAD^^^^^^” ifadesinde doğru olanın git rebase -i HEAD~5 olduğunu düşünüyorum
    Tabii yalnızca doğrusal geçmişi rebase etmeye çalışıyorsanız
    https://stackoverflow.com/questions/2221658/whats-the-difference-between-head-and-head-in-git

  • En büyük farkındalık, tüm commit’lerin hala içeride durduğunu anladığım andı. Tag’ler ve branch’ler yalnızca commit’leri işaret ediyor; branch’in eskiden işaret ettiği commit’ler de kaybolmuş olmuyor
    Birçok komut, hatta muhtemelen neredeyse hepsi yıkıcı değil; bu yüzden branch’in önceki durumlarına kolayca başvurabiliyorsunuz
    git reflog’u görmüştüm ama çoğunlukla sadece “Daha önce üzerinde çalıştığım o branch hangisiydi?” diye hatırlamak için kullanıyordum
    İstenmeyen bir conflict çözümünün tam ortasına düşürebilecek işlemlere karşı yarı sağlıklı bir korku geliştirmiştim. Çünkü genelde yanlış commit’e ya da branch’e referans verip conflict çıkarıyordum
    O korku tamamen geçmiş değil ama en azından rebase gibi işlemler arasında önceki çalışmaları geri getirme konusunda artık epey rahatım

    • Jujutsu bu korkuyu tamamen ortadan kaldırdı
      Bir işlemin ardından conflict çıkıp çıkmayacağını bilmiyorsam, sadece yapıp sonucu görüyorum. Conflict çıkarsa çözüyorum ya da conflict’i yaratan işlemi geri alıyorum; ya da başka yerde yeni bir commit oluşturup conflict’i daha sonra ele alacak şekilde bırakıyorum
      Conflict çıkacağını biliyorsam ilgili branch’i kopyalayıp önceden uyumlu hale getirmeyi deniyorum ya da conflict çıkaran işlemi çalıştırıp çözüm sürecinden geçiyorum. Çözüm dağınık hale gelirse, çözümlerin bir kısmını geri alıp denemeye devam edebiliyor, bir süre erteleyip başka iş yapabiliyor ya da tüm ağacı atabiliyorum
  • Açık konuşmak gerekirse, Git’i bırakıp JJ’ye bakmak lazım
    https://martinvonz.github.io/jj/v0.17.1/
    Sanırım Linus bile Git’in UI’ının berbat olduğunu düşünürdü. JJ’nin iş akışı harika

    • Index’in olmamasına katılmakta zorlanıyorum. Belki bu, bazı iş akışlarını daha basit hale getiriyordur ama ben iyi ya da kötü Git’in index’ine fazla alıştım; bu yüzden çalışma biçimimin epey değişmesi gerekecek gibi görünüyor
      Yine de biraz kurcalamış olmam dışında gerçek işte derinlemesine kullanmış değilim, o yüzden kesin konuşmak zor