Git'te, geçerli commit karmasını aynı commit'deki bir dosyaya nasıl yazabilirim


131

Burada Git kancalarıyla süslü şeyler yapmaya çalışıyorum, ancak bunu nasıl yapacağımı gerçekten bilmiyorum (veya mümkünse).

Yapmam gereken şey şudur: Her kayıtta hashini almak ve ardından bu hash ile commit'deki bir dosyayı güncellemek istiyorum.

Herhangi bir fikir?


12
Temel olarak bir web uygulamam var ve bu uygulamanın yüklü bir sürümünü, o sürümün tam olarak ilişkilendirildiği kesinleştirme ile ilişkilendirmek istiyorum. İlk düşüncem, bir tür about.html dosyasını commit hash ile güncellemekti. Ama git'in nesne modelini inceledikten sonra, bunun imkansız olduğunu fark ettim = /
Felipe Kamakura

29
Bu çok pratik bir sorundur. Ben de karşılaştım!
Li Dong

7
Bana gelince, programımın günlüklere şöyle bir mesaj yazmasını istiyorum: "myprog başlıyor, v.56c6bb2". Bu şekilde, birisi bir hata kaydedip bana günlük dosyalarını gönderirse, programımın tam olarak hangi sürümünün çalıştığını öğrenebilirim.
Edward Falk

5
@Jefromi, gerçek kullanım durumu aslında çok yaygındır ve yeni başlayanlara çok kolay ulaşır. Temel dosyalara bir şekilde "basılmış" gerçek sürüme sahip olmak temel bir ihtiyaçtır ve bunun neden yanlış bir fikir olduğu açık olmaktan çok uzaktır, örneğin manuel revizyon kontrolü hack'lerinde neredeyse tek seçeneğiniz bu olduğu için. (Yeni başlayanları hatırlayın.) Buna ek olarak, birçok projenin sürümü yakalayıp canlı dosyalara damgalayabilecek herhangi bir inşa / kurulum / dağıtım adımına sahip olmadığını ekleyin. Her şeye rağmen, ön taahhüt yerine, ödeme sonrası kancası bu durumlarda bile yardımcı olabilir.
Sz.

Bu imkansız! Bunu yapabilirseniz, SHA-1 karma algoritmasını bozmuşsunuzdur
betontalpfa

Yanıtlar:


82

Aklınızdan geçenlere benzer bir şey yapmanızı tavsiye ederim: SHA1'i derleme / kurulum / dağıtım sürecinin bir parçası olarak oluşturulan izlenmeyen bir dosyaya yerleştirmek. Yapması açıkça kolay ( git rev-parse HEAD > filenameveya belki de git describe [--tags] > filename) ve git'in izlediğinden farklı bir dosyayla sonuçlanmak gibi çılgınca şeyler yapmaktan kaçınıyor.

Kodunuz daha sonra sürüm numarasına ihtiyaç duyduğunda bu dosyaya başvurabilir veya bir oluşturma işlemi bilgileri son ürünle birleştirebilir. İkincisi aslında git'in sürüm numaralarını nasıl elde ettiğidir - derleme süreci sürüm numarasını depodan alır, ardından çalıştırılabilir dosyada oluşturur.


3
Birisi bunun nasıl yapılacağını adım adım açıklayabilir mi? Ya da en azından doğru yönde bir dürtü mü?
Joel Worsham

1
@Joel Ne yapmalı? Hash'i bir dosyaya nasıl koyacağımı söyledim; geri kalanı muhtemelen inşa sürecinizle ilgili bir şey mi? O kısım hakkında sormaya çalışıyorsanız belki yeni bir soru.
Cascabel

1
Benim durumumda, Makefile dosyama her derlemede bir "gitversion.h" dosyası oluşturan bir kural ekledim. Bkz stackoverflow.com/a/38087913/338479
Edward Falk

1
Bunu bir "git-checkout" kancası ile otomatik hale getirebilirsiniz. Sorun, kancaların manuel olarak takılması gerekmesidir.
Edward Falk

14

Mevcut commit karmasını yazmak imkansızdır: gelecekteki commit karmasını önceden hesaplamayı başarırsanız - herhangi bir dosyayı değiştirir değiştirmez değişecektir.

Ancak üç seçenek vardır:

  1. 'Commit kimliğini' artırmak ve bir yere eklemek için bir komut dosyası kullanın. Çirkin
  2. .gitignore, hash'i saklayacağınız dosyayı. Çok kullanışlı değil
  3. İçinde pre-commit, önceki commit karmasını saklayın :) % 99.99 durumda commit'leri değiştirmez / eklemezsiniz, bu yüzden bu çalışacaktır. En kötü durumda, kaynak revizyonunu hala tanımlayabilirsiniz.

Bir kanca senaryosu üzerinde çalışıyorum, 'bittiğinde' buraya göndereceğim, ama yine de - Duke Nukem Forever'ın piyasaya çıkmasından önce :))

Güncelleme : kod .git/hooks/pre-commit:

#!/usr/bin/env bash
set -e

#=== 'prev-commit' solution by o_O Tync
#commit_hash=$(git rev-parse --verify HEAD)
commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
commit_hash=$(echo "$commit" | head -1)
commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300

branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation

# Write it
echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py

Şimdi ihtiyacımız olan tek şey, prev_commit,branchçifti gerçek bir commit karmasına dönüştüren bir araçtır :)

Bu yaklaşımın birleştirme taahhütlerini birbirinden ayırıp anlatamayacağını bilmiyorum. Yakında kontrol edeceğim


13

Birisi beni ident ile ilgili "man gitattributes" bölümüne işaret etti.

ident

Öznitelik kimliği bir yol için ayarlandığında, git, blob nesnesindeki $ Id $ 'ı $ Id: ile değiştirir, ardından 40 karakterlik onaltılık blob nesnesi adı ve ardından ödeme sırasında dolar işareti $ gelir. $ Id: ile başlayan ve çalışma ağacı dosyasında $ ile biten herhangi bir bayt dizisi, giriş sırasında $ Id $ ile değiştirilir.

Düşünürseniz, CVS, Subversion vb. De bunu yapar. Depoya bakarsanız, arşivdeki dosyanın her zaman örneğin $ Id $ içerdiğini görürsünüz. Asla onun genişlemesini içermez. Yalnızca ödeme sırasında metnin genişletilmesi sağlanır.


8
identdosyanın kendisinin hashidir, commit'in hastası değil. Gönderen git-scm.com/book/en/... : "Ancak, bu sonuç sınırlı kullanımı Eğer CVS anahtar kelime ikame kullandım veya Subversion, bir datestamp içerebilir ise - SHA tüm bu yararlı değildir. çünkü oldukça rastgele ve bir SHA'nın diğerinden daha eski mi yoksa daha yeni mi olduğunu bilemezsiniz. " filteriş alır, ancak commit bilgisini bir dosyaya (ve dosyadan) alabilir.
Zach Young

11

Bu, gitattributes içindeki filteröznitelik kullanılarak elde edilebilir . smudgeKaydetme kimliğini ekleyen bir cleankomut ve onu kaldıran bir komut sağlamanız gerekir, böylece eklenen dosya yalnızca commit kimliği nedeniyle değişmez.

Bu nedenle, kesinleştirme kimliği hiçbir zaman dosyanın blobunda saklanmaz; sadece çalışma kopyanızda genişletilmiş. (Aslında commit kimliğini blob'a eklemek sonsuz bir yinelemeli görev haline gelir. ☺) Bu ağacı klonlayan herhangi birinin öznitelikleri kendisi için ayarlaması gerekir.


7
İmkansız görev, yinelemeli görev değil. Kaydetme hash değeri, dosya içeriğine bağlı olan dosya hashine bağlı olan ağaç hashine bağlıdır. Kendi kendine tutarlı olmalısın. SHA-1 hash için bir tür [genelleştirilmiş] sabit nokta bulamazsanız .
Jakub Narębski

1
@Jakub, git'te ortaya çıkan hash'i değiştirmeyen izlenen dosyalar oluşturmaya izin verecek bir tür hile var mı? Karmasını geçersiz kılmanın bir yolu, belki. Bu bir çözüm olacak :)
kolypto

@o_O Tync: Mümkün değil. Değiştirilen dosya, (bir dosyanın) değiştirilmiş karması anlamına gelir - bu, tasarım gereği ve bir karma işlevin tanımı gereğidir.
Jakub Narębski

2
Bu oldukça iyi bir çözümdür, ancak bunun bir depoyu klonladığınızda manuel olarak yüklenmesi gereken kancaları içerdiğini unutmayın.
Edward Falk

7

Taahhüt kutusunun dışında düşünün!

bunu dosya kancalarına / çıkış sonrası

#!/bin/sh
git describe --all --long > config/git-commit-version.txt

Sürüm, kullandığınız her yerde mevcut olacaktır.


3

Aslında bunu yapmak isteyeceğinizi sanmıyorum, çünkü commit'deki bir dosya değiştiğinde, commit'in hash'i de değişir.


1

Git dahili bileşenlerini kullanarak bunun neden zorlu bir problem olduğunu keşfetmeme izin verin. Mevcut commit'in sha1'ini şu şekilde alabilirsiniz:

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

Esasen, tarafından döndürülen iletide sha1 sağlama toplamı çalıştırırsınız git cat-file commit HEAD. Bu mesajı incelerken hemen iki şey sorun olarak ortaya çıkıyor. Biri sha1 ağacı ve ikincisi commit zamanı.

Artık taahhüt süresi, mesajı değiştirerek ve belirli bir zamanda bir taahhüt veya zamanlama yapmanın ne kadar sürdüğünü tahmin ederek kolayca halledilebilir. Asıl mesele, alabileceğiniz ağaç sha1'dir git ls-tree $(git write-tree) | git mktree. Esasen, tüm dosyaların ve sha1 sağlama toplamlarının bir listesi olan ls-ağacından gelen mesajda sha1 sağlama toplamı yapıyorsunuz.

Bu nedenle, sha1 sağlama toplamınız, çemberi tamamlayan ve sha1 kaydına bağlı olan sha1 sağlama toplamına doğrudan bağlı olan sha1 sağlama toplamınıza bağlıdır. Bu yüzden benim kullanabileceğim tekniklerle ilgili döngüsel bir probleminiz var.

Daha az güvenli sağlama toplamlarıyla , dosyanın sağlama toplamını kaba kuvvet yoluyla dosyanın kendisine yazmanın mümkün olduğu gösterilmiştir; ancak sha1 ile bu görevi yerine getiren herhangi bir çalışma bilmiyorum. Bu imkansız değil, ama şu anki anlayışımızla imkansızın yanında (ama kim bilir belki birkaç yıl içinde önemsiz olacak). Bununla birlikte, yine de, bir (blob) sağlama toplamının (ağaç) sağlama toplamının (commit) sağlama toplamını dosyaya yazmanız gerektiğinden, kaba kuvvet uygulamak daha da zordur.


Dosyaları teslim etmenin, ardından bir teslim almanın ve en son kaydetme karmasını her kaynak kod dosyasının başına yorum olarak yerleştirmenin bir yolu var mı? Sonra inşa edip ondan kaçmak?
John Wooten
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.