CVSからGitへの移行:$ Id $同等ですか?


124

シンプルなソースコード管理ツールについて尋ねる多くの質問を読みましたが、Gitは合理的な選択のように思えました。私はそれを稼働させており、これまでのところうまくいきます。CVSについて私が気に入っている点の1つは、バージョン番号の自動インクリメントです。

これは分散リポジトリではあまり意味がないと理解していますが、開発者として、私はこのようなものが欲しい/必要です。理由を説明しましょう:

私はEmacsを使用しています。定期的に調べて、サードパーティパッケージのLispソースファイルの新しいバージョンを探します。ヘッダーによれば、ファイルfoo.elがバージョン1.3であるとします。最新バージョンを調べて、それが1.143や2.6などであることがわかった場合、かなり遅れていることがわかります。

代わりに、40文字のハッシュが2つ表示された場合、どちらが遅いかわからないか、どれだけ後であるかがわかりません。自分がどれだけ古くなっているのかを知るためだけにChangeLogを手動でチェックしなければならないとしたら、私はそれを絶対に嫌います。

開発者として、私が見るように、この礼儀を私の出力を使用する人々に拡張したいと思います(そして、多分私はだれでもだと冗談を言っていますが、それは少しおきましょう)。私は毎回自分の気の数、またはタイムスタンプなどをインクリメントすることを覚えておく必要はありません。それは本当のPITAであり、私は経験からそれを知っています。

それで、私にはどのような選択肢がありますか?$ Id:$に対応できない場合、他にどのようにして探しているものを提供できますか?

私の期待は、エンドユーザーにはGitがインストールされておらず、インストールされていてもローカルリポジトリがないことです(実際、そのように使用できるようにしないと期待しています)。

回答:


67

SHAはバージョンの1つの表現にすぎません(ただし、正規のものです)。git describeコマンドは、他人を提供していますので、非常によくありません。

たとえばgit describeJava memcachedクライアントソースのマスターブランチで実行すると、次のようになります。

2.2-16-gc0cd61a

それは2つの重要なことを言います:

  1. 2.2以降、このツリーにはちょうど16個のコミットがあります
  2. 正確なソースツリーは、誰も他人のクローン上に表示することができます。

たとえば、versionその番号を表示するために、ソースと一緒にファイルをパッケージ化した(または配布用にすべてのコンテンツを書き換えた)としましょう。パッケージ化されたバージョンが2.2-12-g6c4ae7a(リリースではなく、有効なバージョン)であったとしましょう。

あなたは今、あなたは(4つのコミット)している正確にどのように遠くの後ろに見ることができる、そしてあなたは正確にどの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.

1
これを使用すると、マスターにいくつかの修正プログラムが含まれているときに、開発ブランチをマージするときに失敗します。最後のバージョン以降のコミット数は変更されます。誰かが全部でfilter-branch何かを再構築できるので、ハッシュは信頼できません。
LeMike、2014年

記述では、実行可能ファイルに埋め込むのではなく、情報の学習についてのみ説明します。そのgit describeためには、ビルドする直前にコマンドを実行するか、出力をヘッダーファイルに保存するか、コードに値を埋め込む必要があります。
Jesse Chisholm

55

現在、Gitでは$ Id:$がサポートされています。これをファイルのREADMEに対して有効にするには、「README ident」を.gitattributesに入れます。ファイル名のワイルドカードがサポートされています。詳細はman gitattributesを参照してください。


14
これにより、BLOBのsha1が提供されますが、コミットのsha1は提供されません。便利です。コミットの識別子としてだけではありません。
スティーブンジェニングス

4
gitには、$Id$前述のようなキーワード展開メカニズムはありません。保存されるものは、まさにあなたが得るものです。いずれにせよ、バージョンは、特に1つのファイルではなく、コミットを構成するファイルの完全なコレクションに属します(そのアイデアはRCS時代の名残であるか、SCCSがここで責任を負うことになっています... CVSは単なるRCSのフロントエンドを栄光化し、SVNはCVSのように動作しようとしましたが、スタックしました。)
フォンブランド2013年

32

これはOPからの不当な要求ではありません。

私のユースケースは:

  1. 私は自分の個人コードにGitを使用しているため、他のユーザーとのコラボレーションはありません。
  2. 私はそこにシステムBashスクリプトを保管しますが/usr/local/bin、それらは準備ができたときに実行される可能性があります。

同じGitリポジトリーがインストールされた3つの別個のマシンを使用しています。/usr/local/bin手動で "diff -u <repo version> <version in / usr / local / bin>"を実行しなくても、現在使用しているファイルの "バージョン"を知っておくと便利です。

あなたが否定的である人にとって、そこには他のユースケースがあることを覚えておいてください。誰もがGitを「最終的な」場所とするGitリポジトリ内のファイルとの共同作業に使用するわけではありません。

とにかく、私がやった方法は、次のようにリポジトリに属性ファイルを作成することでした:

cat .git/info/attributes
# see man gitattributes
*.sh ident
*.pl ident
*.cgi ident

次に、$ Id $をファイルのどこかに配置します(私はシバンの後に配置します)。

コミット。これは、期待したように自動的に拡張されないことに注意してください。たとえば、ファイルを再coする必要があります。

git commit foo.sh
rm foo.sh
git co foo.sh

そして、次のような展開が表示されます。

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

いくつかの良い情報がある中で、私はGitのリポジトリのためのident文字列を有効にするにはどうすればよいですか?


3
これは現在のコミットではなく現在のファイル(ブロブ)を特定することに注意してください
CharlesB

3
何をgit coすべきか?「git: 'co' is not a git command. See 'git --help'.」というエラーメッセージが表示されますgit checkout
Peter Mortensen

23

これがGitに含まれるかどうかはわかりません。Linus引用するに

「キーワード置換の概念全体はまったくばかげています。リリースツリーをtar-ballとして実行する場合など、実際のコンテンツトラッキングの「外」で実行するのは簡単です。」

ただし、ログを確認するのは非常に簡単です。foo.elの安定ブランチを追跡している場合は、ローカルコピーにない新しいコミットが安定ブランチのログにあることがわかります。CVSの内部バージョン番号をシミュレートする場合は、最後のコミットのタイムスタンプを比較できます。

編集:これを行うには、他の誰かのスクリプトを作成または使用する必要があります。もちろん、これを手動で行うことはできません。


26
ええ、私はキーワード拡張についての長い一連のメールの一部を読みました。Linusの態度は私をgitから完全に引き離すのにほぼ十分でした。
Joe Casadonte 2008

15
ええ、時々彼は礼儀正しさに欠けていますが、彼は通常正しいです、そして彼は間違いなくキーワード拡張の話題にあります。
Bombe

バージョン追跡が必要です。gitは、純粋な開発以外の多くのインフラストラクチャで使用されており、コードを読んで意味があるかどうかを判断できます。しかし、リビジョンコントロールシステムを使用して任意のコンテンツを含むファイルを追跡する場合、公式リリースを知るための何らかの手段が必要です。gitは言うまでもなく、gitログは.ini、.conf、.htmlおよびその他のファイルがプッシュされたマシン上にはありません。
rjt 2017年

7
Linusは、キーワード拡張の1つの側面、つまりリリース追跡にのみコメントしました。しかし、それが唯一の目的ではありません。その引用は男性の態度を明確に示していますが、この主題について何も有用ではありません。典型的な「高貴な方法で明白なことを述べる」政治的トリック、そして群衆はあなたのものです。問題は、群衆の定義がばかであるということです。gitとキーワードの展開で状況を明確に説明しています。馬鹿の一人が「いいえ」と言って、みんな応援しました!
AnrDaemon 2017

1
@AnrDaemonだけでなく、ここで別の回答で述べたように、git $Id$ident属性を介したサポートを追加しており、git自体もLinusの意見に人質ではないことを示しています。
oriPを

21

以前に書いたよう

賢明なバージョン番号を示すIdタグを自動的に生成することは、BazaarなどのDSCMツールでは実行できません。これは、開発のすべてのラインが他のすべてのラインと異なる可能性があるためです。したがって、誰かがファイルのバージョン「1.41」を参照する可能性がありますが、そのファイルのバージョン「1.41」は異なります。

基本的に、$ Id $はBazaar、Git、およびその他の分散ソースコード管理ツールでは意味をなしません。


6
そう、投稿する前に読んだので、根本的な問題のより一般的な解決策を求めました。gitがソリューションを提供できないことと同様に、個々のファイルにバージョン番号を付けたいという要望は正当です。
Joe Casadonte 2008

これはGitが不可能ではなく、すべての分散SCMが不可能であることです。意味のあるバージョン番号が本当に必要な場合は、Subversion、CVS、またはその他の集中システムを使用してください。
Bombe

7
「バージョン番号」の代わりにハッシュを吐き出すことの何が問題になっていますか?ログステートメント、デバッグWebページ、および内部スクリプトの「--version」オプションを使用して、どこで実行されているリビジョンかを簡単に確認できるようにしたいので、その特定のハッシュをチェックアウトして、その動作がなぜであるかを確認できます。デプロイされたアプリの管理を簡素化します...そして、すべてのコミットが$ Id $タグが含まれるすべてのファイルへの変更であると見なすいくつかのコミットフックは必要ありません。
nairbv 2013

1
作業中のファイルのハッシュは、gitでそのIDで検索できる限り、「バージョン」と同じように機能します
Erik Aronesty

2
@Brian-OPの編集により、エンドユーザーはバージョン番号を知りたいが、gitまたはgitログにアクセスできません。この場合、ハッシュは意味のない番号であり、バージョン番号ではありません。DSCMは、このニーズの解決を支援しません。
Jesse Chisholm、

10

私も同じ問題を抱えていました。私は、ハッシュ文字列よりも簡単で、リポジトリに接続しなくてもツールを使用できる人が利用できるバージョンを用意する必要がありました。

私はGitのpre-commitフックを使用してそれを行い、自動的に更新できるようにスクリプトを変更しました。

実行したコミットの数に基づいてバージョンを決定します。2人が同時にコミットし、両方が同じバージョン番号をコミットしていると考える可能性があるため、これはわずかな競合状態ですが、このプロジェクトには多くの開発者がいません。

例として、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)をスクリプトに追加します。これを「tool -updateVersion」として呼び出すと、ツールのupdateVersionが呼び出され、「MYVERSION」の値自体が変更されて終了します(それらが開かれている場合は、他のファイルも更新します(必要に応じて)。

それがセットアップされたら、Gitヘッドに移動して、実行可能な1行のbashスクリプトをで作成し.git/hooks/pre-commitます。

スクリプトは単にGitディレクトリの先頭に移動し、でスクリプトを呼び出します-updateVersion

コミット前のスクリプトをチェックインするたびに、-updateVersionを使用してスクリプトを実行します。次に、MYVERSION変数は、コミット数に基づいて更新されます。マジック!


それで、RubyスクリプトをupdateVersionと呼ばなければなりませ git updateVersionんか?呼び方のサンプルをいくつか載せてください。
rjt 2017年

チェックインしているスクリプトにオプション(-updateVersion)を作成し、 'updateVersion'関数を呼び出します(この場合、スクリプト自体のバージョン番号を変更しようとしています)。次に、-updateVersionを使用してスクリプトを呼び出すonelinerシェルコマンドを作成し、すべてのチェックインの前に自分自身を更新します。
David Ljung Madison Stellar

8

$ Keywords $が必要な場合は、代わりにMercurialを試してみることができますか?必要なものを実装するhgkeyword拡張機能があります。MercurialはとにかくDVCSとして興味深いものです。


8

Gitリポジトリで行われることの1つは、tagオブジェクトを使用することです。これは、あらゆる種類の文字列でコミットにタグを付けるために使用でき、バージョンをマークするために使用できます。git tagすべてのタグを返すコマンドを使用して、リポジトリ内のタグを確認できます。

タグをチェックアウトするのは簡単です。たとえば、タグがある場合、次のようにv1.1そのタグをブランチにチェックアウトできます。

git checkout -b v1.1

これはトップレベルのオブジェクトであるため、そのコミットの履歴全体が表示され、diffの実行、変更、マージが可能になります。

それだけでなく、タグが存続していたとしても、それがメイン行にマージされずに削除されていても、タグは存続します。


6
それでは、gitによってこのタグを自動的にファイルに挿入する方法はありますか?ありがとう!
Joe Casadonte 2008

1
キーワード拡張という意味ですか?私の知る限りではありません。製品をビルドしている場合は、ビルドスクリプトの一部として情報を取得し、ビルドした製品のどこかに挿入できます。最新のタグ、このタグ以降のコミット数、現在のハッシュを示すgit-describeを試してください。
Abizern 2008

はい、タグやその他の関連情報は、のexport-subst機能を使用してgitで自動的にファイルに編集できますgitattributes(5)。もちろん、これはを使用git archiveしてリリースを作成する必要があり、結果のtarファイルでのみ置換の編集が表示されます。
グレッグA.ウッズ

4

私が正しく理解している場合、基本的に、最後に更新してから特定のファイルで発生したコミットの数を知りたいと思います。

最初にリモートオリジンの変更を取得しますが、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

1
したがって、ログは使用しないでください:git rev-list master..origin / master | wc -l
ダスティン

4

人々がどれだけ古くなっているのかというアイデアを人々が入手できるようにしたいだけであれば、Gitはいくつかのかなり簡単な方法でそのことを通知できます。たとえば、トランクとトランクでの最後のコミットの日付を比較します。彼らはgit cherry、トランクに存在せず、トランクに存在しないコミットの数を確認するために使用できます。

これで十分な場合は、バージョン番号なしで提供する方法を探します。

また、あなたが彼らがそれを望んでいると確信しているのでない限り、私は誰にでも礼儀を広げることを気にしないでしょう。:)


日付を比較しても問題ない場合は、DateTImeStampをファイルに入れます。gitには、開発者以外にも多くのユースケースがあります。現場のIT担当者は、現在トラブルシューティングを行っているワークステーションの.INIまたは.confファイルが現在のものに近いかどうかを知る必要があります。
rjt 2017年

単なるタイムスタンプで十分でしょうか?間違ったブランチは魅力的なタイムスタンプを持っているかもしれませんが、それでも正確ではありません。
user2066657

4

リポジトリ内のすべてのサブディレクトリにあるすべてのファイルに拡張を適用するには、次を含むリポジトリ内.gitattributesの最上位ディレクトリ(つまり、通常は.gitignoreファイルを置く場所)にファイルを追加します。

* ident

これが有効であることを確認するには、まず、ファイルの削除や編集など、ファイルを効果的にチェックアウトする必要があります。次に、それらを復元します:

git checkout .

そして、あなたは$Id$次のようなものに置き換えられているはずです:

$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $

からman gitattributes

アイデンティティ

パスに属性identが設定されている場合、Gitはblobオブジェクトの$ Id $を$ Id:に置き換え、チェックアウト時に40文字の16進数のblobオブジェクト名が続き、その後にドル記号$が続きます。ワークツリーファイルで$ Id:で始まり$で終わるバイトシーケンスは、チェックイン時に$ Id $に置き換えられます。

このIDは、ファイルの新しいバージョンがコミットされるたびに変更されます。


3

RCS IDは単一ファイルのプロジェクトには適していますが、他のプロジェクトでは$ Id $はプロジェクトについて何も言いません(ダミーのチェックインをダミーのバージョンファイルに強制しない限り)。

それでも、ファイルごとのレベルまたはコミットレベルで$ Author $、$ Date $、$ Revision $、$ RCSfile $などに相当するものを取得する方法に興味があるかもしれません(キーワードが別の場所に配置する方法)質問)。これらについては答えはありませんが、特にファイル(現在Gitにある)がRCS互換システム(CVS)からのものである場合は、それらを更新する必要があることを確認してください。

このようなキーワードは、ソースがGitリポジトリとは別に配布されている場合に興味深いかもしれません(私もそうです)。私の解決策は次のとおりです:

すべてのプロジェクトには独自のディレクトリがあり、プロジェクトルートには.version、現在のバージョンを説明するコンテンツ(ソースのエクスポート時に使用される名前)という名前のテキストファイルがあります。

次のリリースに向けて作業している間、スクリプトはその.version番号、一部のGitバージョン記述子(などgit describe)および単調なビルド番号.build(およびホストと日付)を、最終的なプログラムにリンクされている自動生成されたソースファイルに抽出します。どのソースから、そしていつ構築されたか。

新しい機能を別々のブランチで開発し、最初に行うのはn(「次へ」の場合).version文字列に追加することです(同じルートからの複数のブランチは同じ一時的な.version番号を使用します)。リリース前に、マージするブランチを決定します(うまくいけば、すべてが同じになります.version)。マージをコミットする前.versionに、次の番号に更新します(マージされた機能に応じて、メジャーまたはマイナー更新)。


3

あなたはgitの情報コミットしたい場合はアクセスをあなたのコードの中に、あなたは持っているが、それを取得するには事前にビルドステップを行うこと。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これらの問題を回避できる手の込んだ方は、読者のための演習として残します。


1

トークンの置換はバージョン管理ツールではなくビルドツールに属していると考える人にも同意します。

リリースにタグが付けられているときに、ソースにバージョンIDを設定するための自動リリースツールが必要です。


2
.INI .confおよび.txtには、通常、ビルドツールはありません。
rjt 2017年

しかし、現在のGitタグを受け取り、それをファイルなどに書き込むリリーススクリプトを一緒にハッキングすることができます。
Marnen Laibow-Koser

1

タグ名とその他の関連情報は、のexport-subst機能を介してGitによって自動的にファイルに直接編集できるようになりましたgitattributes(5)。もちろん、これはを使用git archiveしてリリースを作成する必要があり、結果のtarファイルでのみ置換の編集が表示されます。

たとえば、.gitattributesファイルに次の行を追加します。

* export-subst

次に、ソースファイルに次のような行を追加できます。

#ident  "@(#)PROJECTNAME:FILENAME:$Format:%D:%ci:%cN:%h$"

そして、次のように作成されたリリースでは、このように展開されますgit archive v1.2.0.90

#ident  "@(#)PROJECTNAME:FILENAME:HEAD -> master, tag: v1.2.0.90:2020-04-03 18:40:44 -0700:Greg A. Woods:e48f949"

0

Emacsを使用しているので、幸運かもしれません:)

私は偶然にもこの質問に遭遇しました。また、偶然にも数日前にLivelyから出てきました。ドキュメントにEmacs Lispの活発な部分を含めることができるEmacsパッケージです。正直に言うつもりはありませんが、これを読んで頭に浮かんできました。


0

また、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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.