-
1. Başlangıç
- 1.1 Sürüm Denetimi
- 1.2 Git’in Kısa Tarihçesi
- 1.3 Git Nedir?
- 1.4 Komut Satırı
- 1.5 Git’i Yüklemek
- 1.6 Git’i İlk Defa Kurmak
- 1.7 Yardım Almak
- 1.8 Özet
-
2. Git Temelleri
-
3. Git Dalları
- 3.1 Dallar
- 3.2 Kısaca Dallandırma ve Birleştirme Temelleri
- 3.3 Dal Yönetimi
- 3.4 İş Akışı Dallandırması
- 3.5 Uzak Dallar
- 3.6 Yeniden Temelleme (rebase)
- 3.7 Özet
-
4. Bir Sunucuda Git Kurma
- 4.1 İletişim Kuralları (Protocols)
- 4.2 Bir Sunucuda Git Kurma
- 4.3 SSH Ortak Anahtarınızı Oluşturma
- 4.4 Sunucu Kurma
- 4.5 Git Cini (Daemon)
- 4.6 Akıllı HTTP
- 4.7 GitWeb
- 4.8 GitLab
- 4.9 Üçüncü Taraf Barındırma (Hosting) Seçenekleri
- 4.10 Özet
-
5. Dağıtık Git
- 5.1 Dağıtık İş Akışları
- 5.2 Projenin Gelişiminde Rol Almak
- 5.3 Bir Projeyi Yürütme
- 5.4 Özet
-
6. GitHub
- 6.1 Bir Projeye Katkıda Bulunmak
- 6.2 Proje Bakımı
- 6.3 Kurumsal Yönetim
- 6.4 GitHub’ı otomatikleştirme
- 6.5 Özet
-
7. Git Araçları
- 7.1 Düzeltme Seçimi
- 7.2 Etkileşimli İzlemleme (Staging)
- 7.3 Saklama ve Silme
- 7.4 Çalışmanızı İmzalama
- 7.5 Arama
- 7.6 Geçmişi Yeniden Yazma
- 7.7 Reset Komutunun Gizemleri
- 7.8 İleri Seviye Birleştirme
- 7.9 Rerere
- 7.10 Git’le Hata Ayıklama
- 7.11 Alt Modüller
- 7.12 Demetleme (Bundling)
- 7.13 Git Nesnesini Değiştirme
- 7.14 Kimlik Bilgisi Depolama
- 7.15 Özet
-
8. Git’i Özelleştirmek
- 8.1 Git Yapılandırması
- 8.2 Git Nitelikleri
- 8.3 Git Kancaları (Hooks)
- 8.4 Bir Örnek: Mecburi Git Politikası
- 8.5 Özet
-
9. Git ve Diğer Sistemler
- 9.1 İstemci Olarak Git
- 9.2 Git’e Geçiş
- 9.3 Özet
-
10. Dahili Git Ögeleri
- 10.1 Tesisat ve Döşeme (Plumbing ve Porcelain)
- 10.2 Git Nesneleri
- 10.3 Git Referansları
- 10.4 Packfiles
- 10.5 Refspec
- 10.6 Transfer Protokolleri
- 10.7 Bakım ve Veri Kurtarma
- 10.8 Ortam Değişkenleri
- 10.9 Özet
-
A1. Ek bölüm A: Diğer Ortamlarda Git
- A1.1 Görsel Arayüzler
- A1.2 Visual Studio ile Git
- A1.3 Visual Studio Code ile Git
- A1.4 Eclipse ile Git
- A1.5 Sublime Text ile Git
- A1.6 Bash ile Git
- A1.7 Zsh ile Git
- A1.8 PowerShell ile Git
- A1.9 Özet
-
A2. Ek bölüm B: Git’i Uygulamalarınıza Gömmek
- A2.1 Git Komut Satırı
- A2.2 Libgit2
- A2.3 JGit
- A2.4 go-git
- A2.5 Dulwich
-
A3. Ek bölüm C: Git Komutları
- A3.1 Kurulum ve Yapılandırma Komutları
- A3.2 Proje Oluşturma Komutları
- A3.3 Kısaca Poz (Snapshot) Alma
- A3.4 Dallandırma ve Birleştirme Komutları
- A3.5 Projeleri Paylaşma ve Güncelleme Komutları
- A3.6 İnceleme ve Karşılaştırma Komutları
- A3.7 Hata Ayıklama (Debugging) Komutları
- A3.8 Yamalama (Patching)
- A3.9 E-Posta Komutları
- A3.10 Harici Sistemler
- A3.11 Yönetim
- A3.12 Tesisat (Plumbing) Komutları
8.4 Git’i Özelleştirmek - Bir Örnek: Mecburi Git Politikası
Bir Örnek: Mecburi Git Politikası
Bu bölümde, öğrendiklerinizi kullanarak, özel bir katkı mesaj biçimini kontrol eden ve belirli kullanıcıların bir projedeki belirli alt dizinleri değiştirmesine izin veren bir Git iş akışı oluşturacaksınız. Geliştiricinin itmesinin reddedilip reddedilmeyeceğini bilmesine yardımcı olan istemci betikleri oluşturacak ve politikaları uygulayan sunucu betikleri oluşturacaksınız.
Göstereceğimiz betikler (kısmen zihinsel ataletimizden dolayı) Ruby dilinde yazılmıştır, ancak bir diğer sebebi de yazamıyor olsanız bile, Ruby’nin okunması kolay bir dil olmasıdır. Ancak herhangi bir dil işe yarayacaktır (Git ile birlikte dağıtılan tüm örnek kanca betikleri Perl veya Bash’te yazılmıştır ve örnekleri inceleyerek, bu dillerdeki kancaları görebilirsiniz).
Sunucu Tarafı Kancası
Tüm sunucu tarafı işlemleriniz, hooks
dizininizdeki update
dosyasına gidecektir.
update
kancası, itilen her dal için bir kez çalışır ve üç argüman alır:
-
İtinilen referansın adı
-
O dalın eski sürümü
-
İtilen yeni sürüm
Ayrıca, itmenin SSH üzerinden gerçekleştirilip gerçekleştirilmediğine bağlı olarak iten kullanıcıya da erişiminiz vardır.
Herkesin tek bir kullanıcıyla (örneğin, git
) genel anahtar kimlik doğrulaması yoluyla bağlanmasına izin verdiyseniz, bu kullanıcıya, hangi kullanıcının genel anahtara dayanarak bağlandığını belirleyen ve buna göre bir ortam değişkeni ayarlayan bir kabuk sarmalayıcı (shell wrapper) vermeniz gerekebilir.
Burada, bağlantı kuran kullanıcının $USER
ortam değişkeninde olduğunu varsayacağız, bu nedenle güncelleme betiğiniz ihtiyacınız olan tüm bilgileri toplayarak işe başlar:
#!/usr/bin/env ruby
$refname = ARGV[0]
$oldrev = ARGV[1]
$newrev = ARGV[2]
$user = ENV['USER']
puts "Enforcing Policies..."
puts "(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})"
Evet bunlar global değişkenler. Bizi yargılamayın; bu şekilde göstermek daha kolay.
Belirli Bir Katkı Mesajı Formatını Zorunlu Hale Getirme
Zorlanacağınız ilk konu, her katkı mesajının belirli bir formata uygun olmasını sağlamaktır.
Sırf bir hedefiniz olsun diye, diyelim ki her katkının iş takip sisteminizde bir iş ögesine bağlanmasını istediğiniz için, her katkı mesajının ref: 1234
gibi görünen bir dize içermesi şartını koydunuz.
Her itilen katkı mesajında bu dizenin olup olmadığını kontrol etmeli ve eğer dize herhangi bir katkıda yoksa, itmenin reddedilmesi için çıkış yapmalısınız.
$newrev
ve $oldrev
değerlerini alıp bunları git rev-list
adlı bir Git tesisat komutuna ileterek itilen tüm katkıların SHA-1 değerlerinin bir listesini alabilirsiniz.
Bu, temelde git log
komutudur; ancak varsayılan olarak SHA-1 değerleri dışında hiçbir bilgi yazdırmaz.
Bu nedenle, bir katkı SHA-1 değeri ile diğer bir katkı SHA-1 değeri arasında tanıtılan tüm katkı SHA-1’lerinin bir listesini almak için şöyle bir şey çalıştırabilirsiniz:
$ git rev-list 538c33..d14fc7
d14fc7c847ab946ec39590d87783c69b031bdfb7
9f585da4401b0a3999e84113824d15245c13f0be
234071a1be950e2a8d078e6141f5cd20c1e61ad3
dfa04c9ef3d5197182f13fb5b9b1fb7717d2222a
17716ec0f1ff5c77eff40b7fe912f9f6cfd0e475
Bu çıktıyı alıp, her bir katkı SHA-1’i üzerinden dönebilir, onun için mesajı alabilir ve bir model arayan bir düzenli ifadeye karşı test edebilirsiniz.
Her bir katkı mesajını test etmek için bu katkılardan nasıl katkı mesajını alacağınızı bulmanız gerekmektedir.
Ham katkı verilerini almak için, git cat-file
adlı başka bir tesisat komutunu kullanabilirsiniz.
Bu tesisat komutlarını detaylı olarak Dahili Git Ögeleri bölümünde ele alacağız; ancak şu anda, bu komutun size ne verdiğini aşağıda gösteriyoruz:
$ git cat-file commit ca82a6
tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf
parent 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7
author Scott Chacon <schacon@gmail.com> 1205815931 -0700
committer Scott Chacon <schacon@gmail.com> 1240030591 -0700
changed the version number
Bir katkının SHA-1 değerine sahipken katkı mesajını almanın basit bir yolu, ilk boş satıra gitmek ve o satırdan sonrasını almaktır.
Bunu Unix sistemlerinde sed
komutuyla yapabilirsiniz:
$ git cat-file commit ca82a6 | sed '1,/^$/d'
changed the version number
incantation’ı kullanarak itilmeye çalışılan her katkının mesajını alabilir ve eşleşmeyen herhangi bir şey gördüğünüzde çıkabilirsiniz. İtmeyi reddederek betiği sonlandırmak için sıfırsız (non-zero) çıkış yapın. Yöntemin tamamı şöyle görünüyor:
$regex = /\[ref: (\d+)\]/
# enforced custom commit message format
def check_message_format
missed_revs = `git rev-list #{$oldrev}..#{$newrev}`.split("\n")
missed_revs.each do |rev|
message = `git cat-file commit #{rev} | sed '1,/^$/d'`
if !$regex.match(message)
puts "[POLICY] Your message is not formatted correctly"
exit 1
end
end
end
check_message_format
Bunu update
betiğinize koyarak, kuralınıza uymayan mesajları içeren katkıların reddedilmesini sağlayabilirsiniz.
Kullanıcı Tabanlı bir ACL Sisteminin Uygulanması
Kullanıcıların, hangi projelerin, hangi bölümlerine değişiklik yapmalarına izin verildiğini belirten bir erişim kontrol listesi (ACL) mekanizması eklemek istediğinizi varsayalım.
Bazı kullanıcılar tam erişime sahipken, diğerleri yalnızca belirli alt dizin veya dosyalarad değişiklik yapabilirler.
Bu kısıtlamaları uygulamak için, bu kuralları sunucudaki çıplak Git reponuzda bulunan bir acl
dosyasına yazacaksınız. update
kancası bu kurallara bakacaktır: itilen tüm katkılar için tanıtılan dosyaları görecek ve itme işlemini gerçekleştiren kullanıcının tüm bu dosyalara erişiminin olup olmadığını belirleyecektir.
İlk yapmanız gereken şey ACL’nizi yazmaktır.
Burada, CVS ACL mekanizmasıyla oldukça benzer bir biçim kullanacaksınız: İlk alan avail
veya unavail
; bir sonraki alan, kuralın uygulandığı kullanıcıların virgülle ayrılmış bir listesi, ve son alan ise kuralın uygulandığı dizin (boşluk karakteri açık erişim anlamına gelir) şeklinde bir dizi satır kullanılır.
Tüm bu alanlar bir boru (|
) karakteri ile ayrılmıştır.
Senaryomuzda, birkaç yönetici, doc
dizinine erişimi olan bazı belge yazarları ve yalnızca lib
ve tests
dizinlerine erişimi olan bir geliştiriciniz var ve ACL dosyanız şöyle görünüyor:
avail|nickh,pjhyett,defunkt,tpw
avail|usinclair,cdickens,ebronte|doc
avail|schacon|lib
avail|schacon|tests
Bu veriyi, onu kullanabileceğiniz bir yapıya okuyarak başlıyorsunuz.
Bu örneği basit tutmak için sadece avail
direktiflerini uygulayacaksınız.
İşte, kullanıcı adının anahtar olduğu ve kullanıcının yazma erişimine sahip olduğu yol dizinini içeren ilişkisel bir dizi (array) veren bir yöntem:
def get_acl_access_data(acl_file)
# read in ACL data
acl_file = File.read(acl_file).split("\n").reject { |line| line == '' }
access = {}
acl_file.each do |line|
avail, users, path = line.split('|')
next unless avail == 'avail'
users.split(',').each do |user|
access[user] ||= []
access[user] << path
end
end
access
end
Önceki incelediğiniz ACL dosyasına göre, bu get_acl_access_data
yöntemi aşağıdaki gibi bir veri yapısı döndürür:
{"defunkt"=>[nil],
"tpw"=>[nil],
"nickh"=>[nil],
"pjhyett"=>[nil],
"schacon"=>["lib", "tests"],
"cdickens"=>["doc"],
"usinclair"=>["doc"],
"ebronte"=>["doc"]}
İzinleri düzenledikten sonra, itilen katkıların değiştirdiği yolları belirlemeniz gerekiyor. Böylece iten kullanıcının hepsine erişimi olduğundan emin olabilirsiniz.
git log
komutuna --name-only
seçeneğini ekleyerek, tek bir katkıda hangi dosyaların değiştirildiğini oldukça kolayca görebilirsiniz (Git Temelleri bölümünde bundan kısaca bahsedilmektedir):
$ git log -1 --name-only --pretty=format:'' 9f585d
README
lib/test.rb
get_acl_access_data
yönteminden dönen ACL yapısını kullanarak ve her bir katkıda listelenen dosyaları bu yapıyla karşılaştırarak, kullanıcının tüm katkılarını itmek için erişime sahip olup olmadığını belirleyebilirsiniz:
# only allows certain users to modify certain subdirectories in a project
def check_directory_perms
access = get_acl_access_data('acl')
# see if anyone is trying to push something they can't
new_commits = `git rev-list #{$oldrev}..#{$newrev}`.split("\n")
new_commits.each do |rev|
files_modified = `git log -1 --name-only --pretty=format:'' #{rev}`.split("\n")
files_modified.each do |path|
next if path.size == 0
has_file_access = false
access[$user].each do |access_path|
if !access_path # user has access to everything
|| (path.start_with? access_path) # access to this path
has_file_access = true
end
end
if !has_file_access
puts "[POLICY] You do not have access to push to #{path}"
exit 1
end
end
end
end
check_directory_perms
Sunucunuza itilen yeni katkıların bir listesini git rev-list
kullanarak alırsınız.
Ardından, bu katkıların her biri için değiştirilen dosyaları bulur ve iten kullanıcının değiştirilen tüm yollara erişimi olduğundan emin olursunuz.
Artık kullanıcılarınız, kötü biçimlendirilmiş mesajlara veya belirlenmiş yolların dışında değiştirilmiş dosyalara sahip katkıları itemezler.
Deneme
chmod u+x .git/hooks/update
komutunu çalıştırırsanız, bu kodları yerleştirmeniz gereken dosya olan .git/hooks/update
dosyasına erişim izni verirsiniz. Ardından, uyumsuz bir mesajla bir katkı itmeye çalıştığınızda, aşağıdakine benzer bir çıktı alırsınız:
$ git push -f origin master
Counting objects: 5, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 323 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
Enforcing Policies...
(refs/heads/master) (8338c5) (c5b616)
[POLICY] Your message is not formatted correctly
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master
To git@gitserver:project.git
! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'git@gitserver:project.git'
Burada birkaç ilginç şey var. Öncelikle kancanın çalışmaya başladığı yeri görüyorsunuz.
Enforcing Policies...
(refs/heads/master) (fb8c72) (c56860)
Bunu güncelleme komut dosyanızın en başında yazdırdığınızı unutmayın.
Komut dosyanızın stdout
'a yansıttığı her şey istemciye aktarılacaktır.
Bir sonraki fark edeceğiniz şey hata mesajıdır.
[POLICY] Your message is not formatted correctly
error: hooks/update exited with error code 1
error: hook declined to update refs/heads/master
İlk satır sizin tarafınızdan yazdırıldı, diğer ikisi Git’in size güncelleme komut dosyasının sıfırsız (non-zero) bir durumdan çıktığını ve gönderiminizi reddeden şeyin bu olduğunu söylemesiydi. Son olarak şunu görürsünüz:
To git@gitserver:project.git
! [remote rejected] master -> master (hook declined)
error: failed to push some refs to 'git@gitserver:project.git'
Her reddedilen referans için bir "uzak repo reddedildi" mesajı göreceksiniz ve bu mesaj kancanın başarısız olması nedeniyle özellikle reddedildiğini size bildirir.
Dahası, birinin erişim izni olmayan bir dosyayı düzenlemeye ve içeren bir katkıyı itmeye çalıştığında, benzer bir şey görürler. Örneğin, bir belge yazarı, lib
dizininde bir şeyi değiştiren bir katkıyı itmeye çalışırsa, aşağıdakine benzer bir çıktı alır:
[POLICY] You do not have access to push to lib/test.rb
Artık o update
betiği orada ve çalıştırılabilir olduğu sürece, repo hiçbir zaman istediğiniz biçimde olmayan bir katkı mesajı içermeyecek ve kullanıcılarınız izole edilecekler.
İstemci Tarafı Kancaları
Bu yaklaşımın dezavantajı, kullanıcıların katkı itmelerinin reddedilmesiyle kaçınılmaz olarak ortaya çıkacak olan şikayetlerdir. Dikkatle hazırladıkları çalışmalarının son anda reddedilmesi, son derece sinir bozucu ve kafa karıştırıcı olabilir. Ayrıca, bunu düzeltmek için geçmişlerini düzenlemeleri gerekeceğinden, uygulaması her zaman kolay değildir.
Bu ikileme çözüm, kullanıcıların sunucunun muhtemelen reddedeceği bir şey yaptıklarında onları bilgilendirmek için çalıştırabilecekleri bazı istemci tarafı kancaları sağlamaktır.
Böylece, katkı işlemeden önce ve bu sorunlar daha zor çözülebilir hale gelmeden önce o sorunu düzeltebilirler.
Kancalar bir projenin kopyasıyla aktarılmadığından, bu betikleri başka bir şekilde dağıtmanız ve ardından kullanıcılarınızın bunları .git/hooks
dizinlerine kopyalamalarını ve çalıştırılabilir hale getirmelerini sağlamanız gerekir.
Bu kancaları projenin içinde veya ayrı bir projede dağıtabilirsiniz, ancak Git bunları otomatik olarak kurmaz.
Öncelikle, her katkı kaydedilmeden hemen önce katkı mesajınızı kontrol etmelisiniz, böylece sunucunun kötü biçimlendirilmiş katkı mesajları nedeniyle değişikliklerinizi reddetmeyeceğini bilirsiniz.
Bunu yapmak için, commit-msg
kancasını ekleyebilirsiniz.
İlk argüman olarak geçirilen dosyadan mesajı okuyup, bunu modele karşılaştırırsanız; eşleşme yoksa Git’i katkıyı iptal etmeye zorlayabilirsiniz:
#!/usr/bin/env ruby
message_file = ARGV[0]
message = File.read(message_file)
$regex = /\[ref: (\d+)\]/
if !$regex.match(message)
puts "[POLICY] Your message is not formatted correctly"
exit 1
end
Eğer o betik (.git/hooks/commit-msg
içinde) yerinde ve çalıştırılabilir durumdaysa ve düzgün biçimlendirilmemiş mesajlı bir katkı işlerseniz, şunu görürsünüz:
$ git commit -am 'test'
[POLICY] Your message is not formatted correctly
Bu durumda hiçbir katkı tamamlanmaz. Ancak, mesajınız uygun modeli içeriyorsa, Git katkıyı işlemenize izin verir:
$ git commit -am 'test [ref: 132]'
[master e05c914] test [ref: 132]
1 file changed, 1 insertions(+), 0 deletions(-)
Sonraki adım olarak, ACL kapsamınız dışındaki dosyaları değiştirmediğinizden emin olmak isterseniz.
Projenizin .git
dizini, önceki kullandığınız ACL dosyasının bir kopyasını içeriyorsa, aşağıdaki pre-commit
betiği bu kısıtlamaları sizin için uygulayacaktır:
#!/usr/bin/env ruby
$user = ENV['USER']
# [ insert acl_access_data method from above ]
# only allows certain users to modify certain subdirectories in a project
def check_directory_perms
access = get_acl_access_data('.git/acl')
files_modified = `git diff-index --cached --name-only HEAD`.split("\n")
files_modified.each do |path|
next if path.size == 0
has_file_access = false
access[$user].each do |access_path|
if !access_path || (path.index(access_path) == 0)
has_file_access = true
end
if !has_file_access
puts "[POLICY] You do not have access to push to #{path}"
exit 1
end
end
end
check_directory_perms
Bu betik, sunucu tarafı kısmıyla hemen hemen aynıdır, ancak iki önemli fark vardır:
İlk olarak, ACL dosyası farklı bir yerde bulunur, çünkü bu betik .git
dizininizden değil, çalışma dizininizden çalıştırılır.
Bu nedenle ACL dosyasının yolunu değiştirmeniz gerekmektedir.
Bundan:
access = get_acl_access_data('acl')
şuna:
access = get_acl_access_data('.git/acl')
Diğer önemli fark, değiştirilen dosyaların bir listesini nasıl elde ettiğinizdir. Sunucu tarafı yöntemi, katkı günlüğüne bakar ama bu noktada katkı henüz kaydedilmemiş olduğundan, dosya listenizi izlem alanından almanız gerekir.
şunun yerine:
files_modified = `git log -1 --name-only --pretty=format:'' #{ref}`
bunu kullanmalısınız:
files_modified = `git diff-index --cached --name-only HEAD`
Bu ikisi aradaki yegane farklılıklardır, bunlar dışında, betik aynı şekilde çalışır.
Bir diğer önemli not: sizden yerel makinenizde çalışırken veya uzak makineye iterken aynı kullanıcı adıyla çalışmanız beklenir.
Bu ikisi farklıysa, $user
değişkenini manuel olarak ayarlamanız gerekir.
Burada yapabileceğimiz başka bir şey, kullanıcının ileri-sarmasız (non-fast-forwarded) referanslar itmemesini sağlamaktır. ileri-sarmasız bir referans almak için, zaten ittiğiniz bir katkıyı tekrar düzenlemek veya aynı uzak dal üzerine farklı bir yerel dalı itmek zorundasınız.
Otomatik olarak, sunucunun zaten bu politikayı uygulamak için receive.denyDeletes
ve receive.denyNonFastForwards
ile yapılandırıldığını varsayıyoruz, bu yüzden yakalamaya çalışabileceğiniz tek kaza, zaten itilmiş katkıları yeniden temellendirilmesidir.
İşte bu durumu kontrol eden bir yeniden temellendirme öncesi betiği örneği: Yeniden yazacağınız tüm katkıların bir listesini alır ve bunların herhangi birinin, herhangi bir uzak referansta var olup olmadığını kontrol eder. Bir uzak referanstan ulaşılabilir birini görürse, yeniden temellendirme işlemini iptal eder.
#!/usr/bin/env ruby
base_branch = ARGV[0]
if ARGV[1]
topic_branch = ARGV[1]
else
topic_branch = "HEAD"
end
target_shas = `git rev-list #{base_branch}..#{topic_branch}`.split("\n")
remote_refs = `git branch -r`.split("\n").map { |r| r.strip }
target_shas.each do |sha|
remote_refs.each do |remote_ref|
shas_pushed = `git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}`
if shas_pushed.split("\n").include?(sha)
puts "[POLICY] Commit #{sha} has already been pushed to #{remote_ref}"
exit 1
end
end
end
Bu betik, Düzeltme Seçimi bölümünde ele alınmayan bir sözdizimi kullanır. Zaten yukarı itilmiş katkıları almak için şunu çalıştırarak bir liste alabilirsiniz:
`git rev-list ^#{sha}^@ refs/remotes/#{remote_ref}`
SHA^@
sözdizimi, bu katkının tüm öncellerinde çözülür.
Ulaşılabilir herhangi bir katkı arıyorsunuz ve bu katkı, itmeye çalıştığınız SHA-1’lerin herhangi birinin herhangi bir öncelinden ulaşılamadığı anlamına gelir. Yani ileri-sarma (fast-forward)'dır.
Bu yaklaşımın başlıca dezavantajı çok yavaş olabilmesi ve genellikle gereksiz olmasıdır. Zorla itme (forced push) işlemi yapmazsanız, sunucu sizi uyaracak ve itmeyi kabul etmeyecektir. Ancak, bu ilginç bir egzersizdir ve teorik olarak daha sonra geri dönüp düzeltmeniz gerekebilecek bir yeniden temellendirme işleminden kaçınmanıza yardımcı olabilir.