Programing

CVS에서 Git으로 이동 : $ Id : $ 상당?

lottogame 2020. 7. 14. 08:16
반응형

CVS에서 Git으로 이동 : $ Id : $ 상당?


간단한 소스 코드 제어 도구에 대해 묻는 많은 질문을 읽었으며 Git은 합리적인 선택처럼 보였습니다. 나는 그것을 가지고 있고, 지금까지 잘 작동합니다. CVS에 대해 좋아하는 한 가지 측면은 버전 번호의 자동 증분입니다.

분산 리포지토리에서는 이것이 의미가 없다는 것을 이해하지만 개발자는 이와 같은 것을 원합니다. 이유를 설명하겠습니다 :

나는 Emacs를 사용합니다. 정기적으로 써드 파티 패키지를위한 새로운 버전의 Lisp 소스 파일을 찾습니다. 헤더에 따라 버전 1.3 인 foo.el 파일이 있다고 가정합니다. 최신 버전을 찾아보고 1.143 또는 2.6 또는 그 이상인 것을 알면 내가 상당히 뒤떨어져 있음을 알 수 있습니다.

대신 40 문자 해시가 두 개 있으면 나중에 어떤 것인지 알지 못하거나 나중에 얼마나 많은지 알 수 없습니다. 내가 얼마나 오래된 지에 대한 아이디어를 얻기 위해 ChangeLogs를 수동으로 확인해야한다면 나는 그것을 싫어할 것입니다.

개발자로서, 나는이 예의를 내가 보는 것처럼 내 결과물을 사용하는 사람들에게 확장하고 싶다. (아마도 누군가가 있다는 것을 농담하고 있지만 잠시 동안 그대로 두자.) 나는 매번 저런 수를 늘리거나 타임 스탬프 또는 그와 비슷한 것을 기억하고 싶지 않습니다. 그것은 실제 PITA이며 경험을 통해 알 수 있습니다.

그래서 어떤 대안이 있습니까? $ Id : $에 해당하는 금액을받을 수없는 경우 찾고자하는 것을 어떻게 제공 할 수 있습니까?

필자는 최종 사용자가 Git을 설치하지 않았으며 로컬 저장소를 가지고 있지 않다는 사실을 언급해야합니다 (실제로 그렇게 할 수는 없을 것으로 기대합니다).


SHA는 정식 버전이지만 하나의 버전 표현입니다. git describe명령은 다른 사람들에게 제공하고 아주 잘합니다.

예를 들어, Java memcached 클라이언트 소스 git describe의 마스터 브랜치에서 실행할 때 다음 얻습니다.

2.2-16-gc0cd61a

그것은 두 가지 중요한 것을 말합니다.

  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.

이제 Git에서 $ Id : $가 지원됩니다. README 파일에 사용하려면 "README ident"를 .gitattributes에 넣으십시오 . 파일 이름의 와일드 카드가 지원됩니다. 자세한 내용은 man gitattributes 를 참조하십시오.


이것은 OP의 부당한 요청이 아닙니다.

내 유스 케이스는 다음과 같습니다.

  1. 개인 코드에 Git을 사용하므로 다른 사람들과 공동 작업하지 않습니다.
  2. 나는 시스템 Bash 스크립트를 거기에 보관하고 /usr/local/bin준비가되면 들어갈 수 있습니다 .

동일한 Git 리포지토리가있는 세 개의 별도 시스템을 사용합니다. /usr/local/bin수동으로 "diff -u <repo version> <version in / usr / local / bin>"을 수행하지 않고 현재 파일의 "version"이 무엇인지 아는 것이 좋습니다 .

부정적인 사람들에게는 다른 유스 케이스가 있다는 것을 기억하십시오. 모든 사용자가 Git 리포지토리의 파일을 "최종"위치로 공동 작업하는 데 Git을 사용하는 것은 아닙니다.

어쨌든, 내가 한 방법은 다음과 같이 저장소에 속성 파일을 만드는 것입니다.

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

그런 다음 $ Id $를 파일 어딘가에 넣으십시오 (세방 뒤에 넣는 것을 좋아합니다).

커밋. 이것은 예상대로 자동으로 확장을 수행하지는 않습니다. 예를 들어 파일을 다시 복사해야합니다.

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

And then you will see the expansion, for example:

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

Some good information is in How do I enable the ident string for a Git repository?.


Not sure this will ever be in Git. To quote Linus:

"The whole notion of keyword substitution is just totally idiotic. It's trivial to do "outside" of the actual content tracking, if you want to have it when doing release trees as tar-balls etc."

It's pretty easy to check the log, though - if you're tracking foo.el's stable branch, you can see what new commits are in the stable branch's log that aren't in your local copy. If you want to simulate CVS's internal version number, you can compare the timestamp of the last commit.

Edit: you should write or use someone else's scripts for this, of course, not do this manually.


As I’ve written before:

Having automatically generated Id tags that show a sensible version number is impossible to do with DSCM tools like Bazaar because everybody’s line of development can be different from all others. So somebody could refer to version “1.41” of a file but your version “1.41” of that file is different.

Basically, $Id$ does not make any sense with Bazaar, Git, and other distributed source code management tools.


I had the same problem. I needed to have a version that was simpler than a hash string and available for people using the tool without needing to connect to the repository.

I did it with a Git pre-commit hook and changed my script to be able to automatically update itself.

I base the version off of the number of commits done. This is a slight race condition because two people could commit at the same time and both think they are committing the same version number, but we don't have many developers on this project.

Mine is in Ruby, but it's not terribly complex code. The Ruby script has:

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

And then I have a command-line option (-updateVersion) that calls updateVersion for the tool.

Finally, I go to the Git head and create an executable script in .git/hooks/pre-commit.

The script simply changes to the head of the Git directory and calls my script with -updateVersion.

Every time I check in, the MYVERSION variable is updated based on what the number of commits will be.


If having $Keywords$ is essential for you, then maybe you could try to look at Mercurial instead? It has a hgkeyword extension that implement what you want. Mercurial is interesting as a DVCS anyway.


Something that is done with Git repositories is to use the tag object. This can be used to tag a commit with any kind of string and can be used to mark versions. You can see that tags in a repository with the git tag command, which returns all the tags.

It's easy to check out a tag. For example, if there is a tag v1.1 you can check that tag out to a branch like this:

git checkout -b v1.1

As it's a top level object, you'll see the whole history to that commit, as well as be able to run diffs, make changes, and merges.

Not only that, but a tag persists, even if the branch that it was on has been deleted without being merged back into the main line.


If you're just wanting people to be able to get an idea how far out of date they are, Git can inform them of that in several fairly easy ways. They compare the dates of the last commit on their trunk and your trunk, for example. They can use git cherry to see how many commits have occurred in your trunk that are not present in theirs.

If that's all you want this for, I'd look for a way to provide it without a version number.

Also, I wouldn't bother extending the courtesy to anyone unless you're sure they want it. :)


If I understand correctly, essentially, you want to know how many commits have happened on a given file since you last updated.

First get the changes in the remote origin, but don't merge them into your master branch:

% git fetch

Then get a log of the changes that have happened on a given file between your master branch and the remote origin/master.

% git log master..origin/master foo.el

This gives you the log messages of all the commits that have happened in the remote repository since you last merged origin/master into your master.

If you just want a count of the changes, pipe it to wc. Say, like this:

% git rev-list master..origin/master foo.el | wc -l

RCS IDs are nice for single-file projects, but for any other the $Id$ says nothing about the project (unless you do forced dummy check-ins to a dummy version file).

Still one might be interested how to get the equivalents of $Author$, $Date$, $Revision$, $RCSfile$, etc. on a per file level or at the commit level (how to put them where some keywords are is another question). I don't have an answer on these, but see the requirement to update those, especially when the files (now in Git) originated from RCS-compatible systems (CVS).

Such keywords may be interesting if the sources are distributed separately from any Git repository (that's what I also do). My solution is like this:

Every project has a directory of its own, and in the project root I have a text file named .version which content describes the current version (the name that will be used when exporting the sources).

While working for the next release a script extracts that .version number, some Git version descriptor (like git describe) and a monotonic build number in .build (plus host and date) to an auto-generated source file that is linked to the final program, so you can find out from what source and when it was built.

I develop new features in separate branches, and the first thing I do is add n (for "next") to the .version string (multiple branches originating from the same root would use the same temporary .version number). Before release I decide which branches to merge (hopefully all having the same .version). Before committing the merge, I update .version to the next number (major or minor update, depending on the merged features).


To apply the expansion to all files in all sub-directories in the repository, add a .gitattributes file to the top level directory in the repository (i.e. where you'd normally put the .gitignore file) containing:

* ident

To see this in effect, you'll need to do an effective checkout of the file(s) first, such as deleting or editing them in any way. Then restore them with:

git checkout .

And you should see $Id$ replaced with something like:

$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $

From man gitattributes:

ident

When the attribute ident is set for a path, Git replaces $Id$ in the blob object with $Id:, followed by the 40-character hexadecimal blob object name, followed by a dollar sign $ upon checkout. Any byte sequence that begins with $Id: and ends with $ in the worktree file is replaced with $Id$ upon check-in.

This ID will change every time a new version of the file is committed.


I agree with those who think that token replacement belongs to build tools rather than to version control tools.

You should have some automated release tool to set the version IDs in your sources at the time the release is being tagged.


Since you use Emacs, you might be lucky :)

I've came across this question by coincidence, and also by coincidence I've came by Lively few days ago, an Emacs package which allows having lively pieces of Emacs Lisp in your document. I've not tried it to be honest, but it came to my mind when reading this.


I also came from SCCS, RCS, and CVS (%W% %G% %U%).

I had a similar challenge. I wanted to know what version a piece of code was on any system running it. The system may or may not be connected to any network. The system may or may not have Git installed. The system may or may not have the GitHub repository installed on it.

I wanted the same solution for several types of code (.sh, .go, .yml, .xml, etc). I wanted any person without knowledge of Git or GitHub to be able to answer the question "What version are you running?"

So, I wrote what I call a wrapper around a few Git commands. I use it to mark a file with a version number and some information. It solves my challenge. It may help you.

https://github.com/BradleyA/markit

git clone https://github.com/BradleyA/markit
cd markit

If you want the git commit information accessible into your code, then you have to do a pre-build step to get it there. In bash for C/C++ it might look something like this:

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

with version.h looking like:

#pragma once
const char* git_tag;
const char* git_commit;

Then, wherever you need it in your code #include "version.h" and reference git_tag or git_commit as needed.

And your Makefile might have something like this:

all: package
version:
  ./prebuild.sh
package: version
  # the normal build stuff for your project

This has the benefit of:

  • getting the currently correct values for this build regardless of branching, merging cherry-picking and such.

This implementation of prepublish.sh has the drawbacks of:

  • forcing a recompile even if the git_tag/git_commit didn't change.
  • it does not take into account local modified files that have not been committed but effect the build.
    • use git describe --tags --always --dirty to catch that use-case.
  • pollutes the global namespace.

A fancier prebuild.sh that could avoid these issues is left as an exercise for the reader.

참고URL : https://stackoverflow.com/questions/384108/moving-from-cvs-to-git-id-equivalent

반응형