単純なソースコード管理ツールについて尋ねる一連の質問を読みましたが、Gitは妥当な選択のように思えました。私はそれを実行していますが、今のところうまくいきます。 CVSで気に入っている点の1つは、バージョン番号の自動インクリメントです。
私はこれが分散リポジトリではあまり意味をなさないことを理解していますが、開発者として私はこのようなものが欲しい/必要です。理由を説明しましょう:
私はEmacsを使用しています。定期的に調べて、サードパーティパッケージ用のLISPソースファイルの新しいバージョンを探します。 foo.elというファイルがあるとします。これは、ヘッダーによるとバージョン1.3です。最新バージョンを調べて、それが1.143または2.6などである場合、かなり遅れていることがわかります。
代わりに40文字のハッシュがいくつか表示された場合、どちらがより遅いかがわからないか、どれくらい後のハッシュかがわかりません。自分がどの程度古くなっているかを知るためにChangeLogを手動で確認する必要がある場合は、絶対に嫌いです。
開発者として、私が見ているように、この礼儀を、私の出力を使用する人々に拡張したいと思います(そして、私はだれかがだましているのかもしれませんが、それはしばらく放置しておきましょう)。毎回自分で気になる数字を増やしたり、タイムスタンプなどを覚えておく必要はありません。それは本当のPITAであり、それは経験から知っています。
それで、私にはどんな選択肢がありますか?同等の$ Id:$を取得できない場合、探しているものを他にどのように提供できますか?
私の期待は、エンドユーザーがGitをインストールせず、たとえインストールしたとしてもローカルリポジトリを持たないことです(実際、そのように使用可能にしないことを期待しています)。
SHAは、バージョンの単なる1つの表現です(ただし、正規)。git describe
コマンドは他のものを提供し、非常にうまく機能します。
たとえば、git describe
私の Java memcachedクライアント ソースのマスターブランチで、これを取得します。
2.2-16-gc0cd61a
それは2つの重要なことを言っています:
たとえば、version
ファイルをソースと一緒にパッケージ化(または配布用にすべてのコンテンツを書き換え)して、その番号を表示したとします。パッケージ化されたバージョンが2.2-12-g6c4ae7a
(リリースではなく、有効なバージョン)。
どれだけ遅れているか(4コミット)、およびを正確に確認できるようになりました。
# The RHS of the .. can be Origin/master or empty, or whatever you want.
% git log --pretty=format:"%h %an %s" 2.2-12-g6c4ae7a..2.2-16-gc0cd61a
c0cd61a Dustin Sallings More tries to get a timeout.
8c489ff Dustin Sallings Made the timeout test run on every protocol on every bui
fb326d5 Dustin Sallings Added a test for bug 35.
fba04e9 Valeri Felberg Support passing an expiration date into CAS operations.
現在、Gitで$ Id:$がサポートされています。ファイルに対して有効にするには[〜#〜] readme [〜#〜]「README ident」を。gitattributesに入れます。ファイル名のワイルドカードがサポートされています。詳細については man gitattributes をご覧ください。
これは、OPからの不当なリクエストではありません。
私のユースケースは:
/usr/local/bin
に入るかもしれません。同じGitリポジトリーを持つ3台の別々のマシンを使用します。手動で「diff -u <レポバージョン> </ usr/local/bin>のバージョン」を実行することなく、現在/usr/local/bin
にあるファイルの「バージョン」を知ることは素晴らしいことです。
ネガティブな人には、他にもユースケースがあることを忘れないでください。誰もがGitリポジトリ内のファイルが「最終」ロケーションであるという共同作業にGitを使用しているわけではありません。
とにかく、私がやった方法は、リポジトリに次のような属性ファイルを作成することでした:
cat .git/info/attributes
# see man gitattributes
*.sh ident
*.pl ident
*.cgi ident
次に、ファイルのどこかに$ Id $を配置します(Shebangの後に配置したいです)。
コミット。これは私が期待したように自動的に展開しないことに注意してください。たとえば、ファイルを再コピーする必要があります。
git commit foo.sh
rm foo.sh
git co foo.sh
そして、例えば次のような展開が表示されます:
$ head foo.sh
#!/bin/sh
# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $
Gitリポジトリのident文字列を有効にするには?にいくつかの良い情報があります。
これがGitに含まれるかどうかはわかりません。宛先 引用Linus :
「キーワード置換の概念全体はまったくばかげています。実際のコンテンツトラッキングの「外部」で行うのは、ツリーをtarボールなどとしてリリースするときに必要な場合は簡単です。」
ただし、ログを確認するのは非常に簡単です-foo.elの安定ブランチを追跡している場合、ローカルコピーにない安定ブランチのログにある新しいコミットを確認できます。 CVSの内部バージョン番号をシミュレートする場合、最後のコミットのタイムスタンプを比較できます。
編集:これには、他の人のスクリプトを書くか使用する必要があります。もちろん、これを手動で行うのではありません。
私が書いたように 前 :
理にかなったバージョン番号を示すIDタグを自動的に生成することは、BazaarのようなDSCMツールでは不可能です。誰もが他の開発ラインとは異なる可能性があるからです。そのため、誰かがファイルのバージョン「1.41」を参照できますが、そのファイルのバージョン「1.41」は異なります。
基本的に、$ Id $はBazaar、Git、およびその他の分散ソースコード管理ツールでは意味がありません。
同じ問題がありました。ハッシュ文字列よりもシンプルで、リポジトリに接続することなくツールを使用する人々が利用できるバージョンが必要でした。
Gitの事前コミットフックを使用して実行し、スクリプトを変更して自動的に更新できるようにしました。
コミット数に基づいてバージョンを決定します。これはわずかな競合状態です。2人が同時にコミットする可能性があり、どちらも同じバージョン番号をコミットしていると考えていますが、このプロジェクトには多くの開発者がいません。
私のものはRubyにありますが、それほど複雑なコードではありません。 Rubyスクリプトには:
MYVERSION = '1.090'
## Call script to do updateVersion from .git/hooks/pre-commit
def updateVersion
# We add 1 because the next commit is probably one more - though this is a race
commits = %x[git log #{$0} | grep '^commit ' | wc -l].to_i + 1
vers = "1.%0.3d" % commits
t = File.read($0)
t.gsub!(/^MYVERSION = '(.*)'$/, "MYVERSION = '#{vers}'")
bak = $0+'.bak'
File.open(bak,'w') { |f| f.puts t }
perm = File.stat($0).mode & 0xfff
File.rename(bak,$0)
File.chmod(perm,$0)
exit
end
そして、ツールのupdateVersionを呼び出すコマンドラインオプション(-updateVersion)があります。
最後に、Gitヘッドに移動して、.git/hooks/pre-commit
に実行可能なスクリプトを作成します。
スクリプトは単にGitディレクトリの先頭に変更され、-updateVersion
でスクリプトを呼び出します。
チェックインするたびに、MYVERSION変数はコミット数に基づいて更新されます。
Gitリポジトリで行われることは、tag
オブジェクトを使用することです。これは、コミットに任意の種類の文字列をタグ付けするために使用でき、バージョンをマークするために使用できます。リポジトリ内のタグは、すべてのタグを返すgit tag
コマンドで確認できます。
タグをチェックアウトするのは簡単です。たとえば、タグv1.1
がある場合、次のようにそのタグをブランチにチェックアウトできます。
git checkout -b v1.1
これはトップレベルのオブジェクトなので、そのコミットの履歴全体が表示され、差分の実行、変更、マージが可能になります。
それだけでなく、タグが存在するブランチがメインラインにマージされずに削除された場合でも、タグは保持されます。
$ Keywords $が必要な場合は、代わりに Mercurial を参照してください。必要なものを実装するhgkeyword拡張があります。とにかくDVCSとしてMercurialは興味深いです。
人々がどれだけ古くなっているかを知ることができるようにしたいだけなら、Gitはそれをいくつかのかなり簡単な方法で知らせることができます。たとえば、トランクとトランクでの最後のコミットの日付を比較します。 git cherry
トランクで発生したコミットのうち、コミットに存在しないコミットの数を確認します。
これで十分な場合は、バージョン番号なしで提供する方法を探します。
また、あなたが彼らがそれを望んでいると確信しない限り、私は誰にでも礼儀を広げることを気にしません。 :)
RCS IDは単一ファイルプロジェクトには適していますが、その他の場合、$ Id $はプロジェクトについて何も言いません(ダミーバージョンファイルへの強制的なダミーチェックインを行わない限り)。
それでも、ファイルレベルごとまたはコミットレベルで$ Author $、$ Date $、$ Revision $、$ RCSfile $などに相当するものを取得する方法に興味があるかもしれません質問)。これらについては答えがありませんが、特にファイル(現在Gitにあります)がRCS互換システム(CVS)からのものである場合は、それらを更新する必要性があります。
このようなキーワードは、ソースがGitリポジトリとは別に配布されている場合に興味深いかもしれません(私もそうしています)。私の解決策はこのようなものです:
すべてのプロジェクトには独自のディレクトリがあり、プロジェクトルートには.version
という名前のテキストファイルがあり、コンテンツには現在のバージョン(ソースのエクスポート時に使用される名前)が記述されています。
次のリリースの作業中、スクリプトはその.version
番号、一部のGitバージョン記述子(git describe
など)、および.build
の単調なビルド番号(およびホストと日付)を自動抽出します。最終プログラムにリンクされている生成されたソースファイル。これにより、どのソースからいつビルドされたかを確認できます。
新しい機能を個別のブランチで開発し、最初に行うことは、n
(「次」)を.version
文字列に追加することです(同じルートからの複数のブランチは同じ一時.version
番号)。リリース前に、どのブランチをマージするかを決定します(すべてのブランチが同じ.version
を持っていることが望ましい)。マージをコミットする前に、.version
を次の番号に更新します(マージされた機能に応じて、メジャーまたはマイナーアップデート)。
基本的に正しく理解していれば、最後に更新してから特定のファイルで何件のコミットが発生したかを知りたいと思うでしょう。
最初にリモートOriginで変更を取得しますが、master
ブランチにマージしないでください:
% git fetch
次に、master
ブランチとリモートOrigin/master
の間の特定のファイルで発生した変更のログを取得します。
% git log master..Origin/master foo.el
これにより、Origin/master
をmaster
に最後にマージしてからリモートリポジトリで発生したすべてのコミットのログメッセージが表示されます。
変更のカウントだけが必要な場合は、wc
にパイプしてください。次のように言ってください:
% git rev-list master..Origin/master foo.el | wc -l
リポジトリ内のすべてのサブディレクトリ内のすべてのファイルに展開を適用するには、リポジトリの最上位ディレクトリ(つまり、通常.gitattributes
ファイルを置く場所)に.gitignore
ファイルを追加します。
* ident
これを実際に確認するには、ファイルの削除や編集など、ファイルを効果的にチェックアウトする必要があります。次に、それらを復元します。
git checkout .
そして、あなたは$Id$
が次のようなものに置き換えられるのを見るでしょう:
$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $
man gitattributes
から:
ident
属性identがパスに設定されている場合、Gitはblobオブジェクトの$ Id $を$ Id:に置き換え、40文字の16進数blobオブジェクト名、チェックアウト時にドル記号$を続けます。ワークツリーファイルで$ Id:で始まり$で終わるバイトシーケンスは、チェックイン時に$ Id $に置き換えられます。
このIDは、ファイルの新しいバージョンがコミットされるたびに変更されます。
トークンの置き換えはバージョン管理ツールではなくビルドツールに属すると考える人々に同意します。
リリースにタグを付けるときに、ソースにバージョンIDを設定する自動リリースツールが必要です。
Gitコミット情報accessibleをコードに追加したい場合は、haveを使用してビルド前の手順を実行します。 C/C++のbashでは、次のようになります。
prebuild.sh
#!/bin/bash
commit=$(git rev-parse HEAD)
tag=$(git describe --tags --always ${commit})
cat <<EOF >version.c
#include "version.h"
const char* git_tag="${tag}";
const char* git_commit="${commit}";
EOF
version.h
のように見える:
#pragma once
const char* git_tag;
const char* git_commit;
次に、コード内の必要な場所#include "version.h"
と必要に応じてgit_tag
またはgit_commit
を参照します。
そして、あなたのMakefile
は次のようなものになるでしょう:
all: package
version:
./prebuild.sh
package: version
# the normal build stuff for your project
これには次の利点があります。
prepublish.sh
のこの実装には、次の欠点があります。
git_tag
/git_commit
が変更されていない場合でも、再コンパイルを強制します。git describe --tags --always --dirty
を使用して、そのユースケースをキャッチします。これらの問題を回避できる手の込んだprebuild.sh
は、読者のための演習として残されています。
Emacsを使用しているので、幸運かもしれません:)
私は偶然にもこの質問に出くわしました。また、偶然にも Lively で、ドキュメントにEmacs LISPの活気のある部分を含めることができるEmacsパッケージを見つけました。私はそれを正直にしようとはしませんでしたが、これを読むときに思い浮かびました。
また、SCCS、RCS、CVSからも来ました(%W% %G% %U%
)。
同様の課題がありました。コードを実行しているシステム上にあるコードのバージョンを知りたいと思いました。システムは、ネットワークに接続されている場合とされていない場合があります。システムにはGitがインストールされている場合とされていない場合があります。システムにはGitHubリポジトリがインストールされている場合とされていない場合があります。
いくつかのタイプのコード(.sh、.go、.yml、.xmlなど)に同じソリューションが必要でした。 GitまたはGitHubの知識のない人が質問に答えられるようにしたかった「どのバージョンを実行していますか?」
そこで、いくつかのGitコマンドのラッパーと呼ぶものを書きました。バージョン番号といくつかの情報でファイルをマークするために使用します。それは私の挑戦を解決します。それはあなたを助けるかもしれません。
https://github.com/BradleyA/markit
git clone https://github.com/BradleyA/markit
cd markit