Tương đương Git cho số sửa đổi là gì?


244

Chúng tôi sử dụng SVN tại nơi làm việc, nhưng đối với các dự án cá nhân của tôi, tôi đã quyết định sử dụng Git. Vì vậy, tôi đã cài đặt Git ngày hôm qua và tôi tự hỏi số sửa đổi tương đương trong Git là gì .

Giả sử chúng tôi làm việc trên phiên bản 3.0.8 và mọi sửa lỗi đều có số sửa đổi riêng mà chúng tôi có thể sử dụng khi nói về sửa lỗi này. Vậy nếu tôi gắn thẻ mã trong Git đến 3.0.8 thì tôi có thể sử dụng làm số sửa đổi hoặc một số loại nhận dạng chi tiết khác? Tôi thấy băm không thân thiện với con người.



Có một bài viết cho một trong những giải pháp có thể. Nó có thể trông hơi nặng nề nhưng được tích hợp vào đầu ra "git log" và không yêu cầu thêm lệnh nào ngoài "git đẩy / kéo / tìm nạp".
Dmitry Pavlenko

Thật không may bài viết được liên kết từ @DmitryPavlenko nằm trên một miền chết: gitsvn.x10.mx. Không có dấu hiệu của chủ đề, sẽ khó có ai tìm thấy nó ở nơi khác.
Michael Donohue

Lưu ý: không cần viết tắt nhiều hơn với mô tả git: xem stackoverflow.com/a/41308073/6309
VonC

1
Không, Laurence Gonsalves, đây không phải là bản sao của "làm thế nào để có được số lượng cam kết git?" - đây là về số phiên bản và mặc dù số lượng cam kết có thể được thay đổi để trông hơi giống nhau - phiên bản băm rất khác so với số lượng cam kết :-)
David Svarrer

Câu trả lời:


149

Tin tốt hay xấu cho bạn, băm đó là số sửa đổi. Tôi cũng gặp rắc rối với điều này khi thực hiện chuyển đổi từ SVN sang git.

Bạn có thể sử dụng "gắn thẻ" trong git để gắn thẻ một phiên bản nhất định làm "phát hành" cho một phiên bản cụ thể, giúp dễ dàng tham khảo bản sửa đổi đó. Kiểm tra bài blog này .

Điều quan trọng cần hiểu là git không thể có số sửa đổi - hãy nghĩ về bản chất phi tập trung. Nếu người dùng A và B đều cam kết với kho lưu trữ cục bộ của họ, làm thế nào git có thể gán một số sửa đổi liên tiếp một cách hợp lý? A không có kiến ​​thức về B trước khi họ đẩy / kéo những thay đổi của nhau.

Một điều khác để xem xét là phân nhánh đơn giản hóa cho các nhánh bugfix:

Bắt đầu với một bản phát hành: 3.0.8. Sau đó, sau khi phát hành, làm điều này:

git branch bugfixes308

Điều này sẽ tạo ra một nhánh cho các lỗi. Kiểm tra chi nhánh:

git checkout bugfixes308

Bây giờ thực hiện bất kỳ thay đổi sửa lỗi bạn muốn.

git commit -a

Cam kết chúng và chuyển trở lại nhánh chính:

git checkout master

Sau đó kéo theo những thay đổi từ các chi nhánh khác:

git merge bugfixes308

Bằng cách đó, bạn có một nhánh sửa lỗi dành riêng cho bản phát hành, nhưng bạn vẫn đang kéo các thay đổi lỗi vào thân cây phát triển chính của mình.


11
Tôi hiểu rằng hàm băm là số sửa đổi nhưng tôi hy vọng nó không phải là :-))) cảm ơn bạn đã giải thích rất hay và cho đề xuất ngay bây giờ để giải quyết nó.
Radek

3
Không có gì. Tôi đã rất thất vọng với git khi lần đầu tiên nhặt nó từ SVN, nhưng bây giờ tôi lại xoay theo cách khác ...
makdad

4
CSONG, đã được một lúc kể từ khi tôi đăng bài này, nhưng hãy nhớ rằng bạn cũng có thể thực hiện "git checkout -b new_branch_name" để thực hiện "git Branch foo" và "git checkout foo" dưới dạng một lớp lót.
makdad

1
Tôi có đúng rằng băm là băm "đúng" và thậm chí không tuần tự từ xa không? Vì vậy, quan trọng, nếu cơ sở dữ liệu lỗi nói fixed in 547cc3e..c4b2ebavà bạn có một số sửa đổi khác, bạn không biết liệu mã của bạn có được phép sửa hay không?! Chắc chắn các gits tại trung tâm git có một giải pháp cho việc này?!?!
Olie

3
Trong SVN, thực tế là một lỗi đã được sửa trong r42 không cho bạn biết liệu nó cũng đã được sửa trong r43 ngay khi bạn sử dụng các nhánh thực sự.
Matthieu Moy

186

Với Git hiện đại (1.8.3.4 trong trường hợp của tôi) và không sử dụng các nhánh bạn có thể làm:

$ git rev-list --count HEAD
68

22
Cân nhắc sử dụnggit rev-list --count --first-parent HEAD
Flimm

8
Đưa ra thông tin này (số 68), có cách nào để xác định sửa đổi để lấy lại mã không? Giả sử "sửa đổi 68" được phát hành cho môi trường thử nghiệm, quá trình phát triển sẽ tiếp tục và sau đó, nhà phát triển cần phải lấy lại "phiên bản 68" từ kiểm soát nguồn. Làm thế nào anh ta sẽ nhắm mục tiêu phiên bản cụ thể để sao chép? Hay tôi đang thiếu một cái gì đó về Git khiến điều này không cần thiết?
David

9
Hãy nhớ rằng giải pháp này sẽ mang lại kết quả khác nhau cho các nhà phát triển khác nhau. Ngoài ra, tính toán ngược từ "đếm" đến cam kết sẽ mang lại các cam kết khác nhau cho các nhà phát triển khác nhau !! Điều này là do tính chất phân tán của Git và các cam kết xảy ra trong các kho khác nhau trong cùng một khoảng thời gian nhưng có thể không được tính vào git rev-list --count HEADtùy thuộc vào thời điểm các lần đẩy và kéo cuối cùng được thực hiện.
Jason

2
@Jason, nhận xét của David về việc thêm --first-parentđịa chỉ mối quan tâm của bạn? Tôi ghét phải tránh một giải pháp có vẻ đơn giản nhất vì trường hợp cạnh hiếm gặp nếu có cách giải quyết đơn giản không kém hoặc cách để làm cho nó mạnh mẽ hơn.
MarkHu

4
@MarkHu, --first-parentgiúp. Miễn là không có việc đánh trả nào được thực hiện và cùng một nhánh luôn được sử dụng để tạo các bản phát hành (và tính số phát hành này, tất nhiên), tôi nghĩ rằng điều này có thể được sử dụng. Mặc dù vậy, tôi vẫn không chắc chắn rằng nó sẽ luôn xác định duy nhất cam kết mà bản phát hành đến từ đó. Có rất nhiều điều có thể sai ở đây ... nhưng hiện tại tôi không thể nghĩ ra thứ gì đó chắc chắn sẽ phá vỡ điều này (đưa ra những tuyên bố "miễn là" ở trên của tôi). Các git describephương pháp được đề cập trong câu trả lời khác là con đường để đi. Tạo một thẻ nếu bạn muốn một cái gì đó con người có thể đọc được.
Jason

104

Các git describelệnh tạo ra một tên có thể đọc được một chút con người hơn là đề cập đến một cụ thể cam kết. Ví dụ: từ tài liệu:

Với một cái gì đó như git.git cây hiện tại, tôi nhận được:

[torvalds@g5 git]$ git describe parent
v1.0.4-14-g2414721

tức là người đứng đầu hiện tại của nhánh "cha mẹ" của tôi dựa trên v1.0.4, nhưng vì nó có một vài cam kết trên đó, mô tả đã thêm số lần xác nhận bổ sung ("14") và tên đối tượng viết tắt cho cam kết chính nó ("2414721") ở cuối.

Miễn là bạn sử dụng các thẻ được đặt tên hợp lý để gắn thẻ các bản phát hành cụ thể, điều này có thể được coi là tương đương với "số sửa đổi" của SVN.


7
Tôi chỉ muốn lưu ý rằng điều này chỉ hoạt động nếu gitkho lưu trữ của bạn đã có thẻ; nếu không, bạn có thể nhận được mô tả git thất bại với "fatal: Không tìm thấy tên, không thể mô tả bất cứ điều gì." - Tràn ngăn xếp ; có nghĩa là bạn phải tự thiết lập thẻ.
sdaau

14
@sdaau: Nếu bạn đang sử dụng điều này trong một kịch bản hoặc một cái gì đó và muốn git describekhông bao giờ thất bại, hãy sử dụng git describe --alwaystùy chọn.
Greg Hewgill

Có thể đầu ra của git describeđược sử dụng để tìm cam kết nguồn, bằng cách nào đó? Ý tôi là viết tắt các cam kết trong nhật ký.
Lii

@Lii: "Cam kết nguồn" nghĩa là gì? Cả thẻ gần nhất ( v1.0.4) và id xác nhận gần đây nhất ( 2414721) đã là một phần của đầu ra mô tả git.
Greg Hewgill

@GregHewgill: Vâng, cảm ơn, khi tôi hỏi câu hỏi tôi đã không nhận ra rằng "tên đối tượng viết tắt" là một giá trị có thể được sử dụng để xác định cam kết. Thật tuyệt vời!
Lii

67

Các áp phích khác là đúng, không có "số sửa đổi".

Tôi nghĩ cách tốt nhất là sử dụng Thẻ cho "phát hành"!

Nhưng tôi đã sử dụng các số sau để sửa đổi số giả (chỉ để khách hàng thấy các bản sửa đổi và tiến trình, vì họ muốn có các bản sửa đổi tăng dần từ git khi họ sử dụng để lật đổ).

Hiển thị "phiên bản hiện tại" của "ĐẦU" được mô phỏng bằng cách sử dụng:

git rev-list HEAD | wc -l

Nhưng nếu khách hàng nói với tôi rằng có lỗi trong "sửa đổi" 1302 thì sao?

Để làm điều này, tôi đã thêm phần sau vào phần [bí danh] trong ~ / .gitconfig:

show-rev-number = !sh -c 'git rev-list --reverse HEAD | nl | awk \"{ if(\\$1 == "$0") { print \\$2 }}\"'

bằng cách sử dụng git show-rev-number 1302sau đó sẽ in băm cho "sửa đổi" :)

Tôi đã thực hiện một bài viết trên Blog (bằng tiếng Đức) về "kỹ thuật" đó một thời gian trước đây.


@Radek - "đôi khi cần biết 'thay đổi mã = ​​cam kết' đã sửa lỗi gì đó" - thì git bisect(liên kết) là công cụ thích hợp để xác định những gì đã thay đổi khi bởi ai.
michael

@Radek Vâng, đó là một con số ngày càng tăng. Nó chỉ đếm các bản sửa đổi mà bạn đã đăng ký trên TRƯỚC. Vì vậy, mỗi cam kết là một phiên bản mới. Điều này sẽ không làm việc cho các chi nhánh khác nhau.
OderWat

1
Tôi thích giải pháp của bạn. Xin lưu ý rằng bạn có thể đơn giản hóa nó: show-rev-number =! Sh -c 'git rev-list --reverse HEAD | awk NR == $ 0 '
avner

@avner Cảm ơn bạn! Tôi đã không sử dụng nhiều awk trong cuộc sống của mình, rõ ràng :)
OderWat

3
Tôi đã phải sử dụnggit rev-list --reverse HEAD | awk "{ print NR }" | tail -n 1
Gerry

27

Git không có cùng khái niệm về số sửa đổi như lật đổ. Thay vào đó, mỗi ảnh chụp nhanh được thực hiện với một cam kết được gắn thẻ bằng tổng kiểm tra SHA1. Tại sao? Có một số vấn đề với revno đang chạy trong hệ thống kiểm soát phiên bản phân tán:

Đầu tiên, vì sự phát triển hoàn toàn không phải là tuyến tính, nên việc đính kèm một số khá khó khăn như một vấn đề cần giải quyết theo cách sẽ thỏa mãn nhu cầu của bạn với tư cách là một lập trình viên. Cố gắng khắc phục điều này bằng cách thêm một số có thể nhanh chóng trở thành vấn đề khi số đó không hoạt động như bạn mong đợi.

Thứ hai, số sửa đổi có thể được tạo ra trên các máy khác nhau. Điều này làm cho việc đồng bộ hóa các số khó hơn nhiều - đặc biệt là khi kết nối là một chiều; bạn thậm chí có thể không có quyền truy cập vào tất cả các máy có kho lưu trữ.

Thứ ba, trong git, phần nào được tiên phong bởi hệ thống OpenCM hiện không còn tồn tại, danh tính của một cam kết (cam kết là gì) tương đương với tên của nó (id SHA). Đây đặt tên = sắc khái niệm này là rất mạnh. Khi bạn ngồi với một tên cam kết trong tay, nó cũng xác định cam kết một cách không thể tha thứ. Điều này lần lượt cho phép bạn kiểm tra tất cả các cam kết của bạn trở lại lần đầu tiên xem có bị hỏng với git fscklệnh không.

Bây giờ, vì chúng tôi có DAG (Đồ thị theo chu kỳ được điều hướng) và chúng tạo thành cây hiện tại, chúng tôi cần một số công cụ để giải quyết vấn đề của bạn : Làm thế nào để chúng tôi phân biệt các phiên bản khác nhau. Đầu tiên, bạn có thể bỏ qua một phần của hàm băm nếu tiền tố đã cho, 1516bd nói, xác định duy nhất cam kết của bạn. Nhưng điều này cũng khá giả. Thay vào đó, mẹo là sử dụng thẻ và hoặc các nhánh. Thẻ hoặc chi nhánh gần giống với "thanh màu vàng ghi chú" mà bạn đính kèm với một cam kết SHA1 đã cho. Về bản chất, các thẻ có nghĩa là không di chuyển trong khi một nhánh sẽ di chuyển khi các xác nhận mới được thực hiện cho CHÍNH của nó. Có nhiều cách để đề cập đến một cam kết xung quanh thẻ hoặc chi nhánh, xem trang man của git-rev-parse.

Thông thường, nếu bạn cần làm việc trên một đoạn mã cụ thể, đoạn đó đang trải qua các thay đổi và như vậy sẽ là một nhánh có tên chủ đề nói. Tạo nhiều nhánh (20-30 cho mỗi lập trình viên không phải là chưa từng thấy, với một số 4-5 được xuất bản để những người khác làm việc) là mẹo để git hiệu quả. Mỗi phần công việc nên bắt đầu như một nhánh riêng của nó và sau đó được hợp nhất khi nó được thử nghiệm. Các nhánh chưa được công bố có thể được viết lại hoàn toàn và phần phá hủy lịch sử này là một lực lượng của git.

Khi sự thay đổi được chấp nhận thành chủ, nó phần nào đóng băng và trở thành khảo cổ học. Tại thời điểm đó, bạn có thể gắn thẻ nó, nhưng thông thường hơn một tham chiếu đến cam kết cụ thể được thực hiện trong trình theo dõi lỗi hoặc trình theo dõi vấn đề thông qua tổng số sha1. Các thẻ có xu hướng được dành riêng cho các phiên bản va chạm và các điểm nhánh cho các nhánh bảo trì (đối với các phiên bản cũ).


18

Nếu bạn quan tâm, tôi sẽ tự động quản lý số phiên bản từ git infos ở đây theo định dạng

<major>.<minor>.<patch>-b<build>

trong đó bản dựng là tổng số lần xác nhận. Bạn sẽ thấy mã thú vị trong Makefile. Đây là phần có liên quan để truy cập vào phần khác nhau của số phiên bản:

LAST_TAG_COMMIT = $(shell git rev-list --tags --max-count=1)
LAST_TAG = $(shell git describe --tags $(LAST_TAG_COMMIT) )
TAG_PREFIX = "latex-tutorial-v"

VERSION  = $(shell head VERSION)
# OR try to guess directly from the last git tag
#VERSION    = $(shell  git describe --tags $(LAST_TAG_COMMIT) | sed "s/^$(TAG_PREFIX)//")
MAJOR      = $(shell echo $(VERSION) | sed "s/^\([0-9]*\).*/\1/")
MINOR      = $(shell echo $(VERSION) | sed "s/[0-9]*\.\([0-9]*\).*/\1/")
PATCH      = $(shell echo $(VERSION) | sed "s/[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/")
# total number of commits       
BUILD      = $(shell git log --oneline | wc -l | sed -e "s/[ \t]*//g")

#REVISION   = $(shell git rev-list $(LAST_TAG).. --count)
#ROOTDIR    = $(shell git rev-parse --show-toplevel)
NEXT_MAJOR_VERSION = $(shell expr $(MAJOR) + 1).0.0-b$(BUILD)
NEXT_MINOR_VERSION = $(MAJOR).$(shell expr $(MINOR) + 1).0-b$(BUILD)
NEXT_PATCH_VERSION = $(MAJOR).$(MINOR).$(shell expr $(PATCH) + 1)-b$(BUILD)

9

Hàm Bash:

git_rev ()
{
    d=`date +%Y%m%d`
    c=`git rev-list --full-history --all --abbrev-commit | wc -l | sed -e 's/^ *//'`
    h=`git rev-list --full-history --all --abbrev-commit | head -1`
    echo ${c}:${h}:${d}
}

xuất ra một cái gì đó như

$ git_rev
2:0f8e14e:20130220

Đó là

commit_count:last_abbrev_commit:date_YYmmdd

Điều đó có thể hữu ích, nhưng nếu ai đó quan tâm đến số phiên bản gia tăng, họ sẽ trao đổi vị trí trường để hàm băm (không tăng) là cuối cùng.
MarkHu

8

Hàm băm SHA1 của cam kết tương đương với số sửa đổi Subversion.


7
Thật không may, nó có các thuộc tính khá khác nhau từ một số sửa đổi. Nó khá dài và không tăng đơn điệu. Đoán rằng đó là cái giá phải trả cho việc phân phối ...
CodeInChaos

1
@CodeInChaos: Tôi biết những gì bạn đang nhận được, nhưng nói chung có thể đề cập đến các cam kết git chỉ với 6 hoặc 8 ký tự đầu tiên của mã băm.
Chris Pitman

5
@Radek: Chúng không được đảm bảo duy nhất (mặc dù nếu bạn tìm thấy một vụ va chạm, bạn có thể giành được một số lượng nhỏ người nổi tiếng).
Slartibartfast

8
@Radek Theo en.wikipedia.org/wiki/Collision_attack , với 4 ký tự băm bạn có Id 16 bit, có nghĩa là trong một repo có 256 (= 2 ^ (16/2)) cam kết có 50 % cơ hội rằng hai lần xác nhận có cùng một tiền tố bốn char (và với 65536 lần xác nhận thì chắc chắn, kể từ đó, phạm vi của Id 4-char đã hết). Khi bạn thêm một char, bạn có Id 20 bit, điều đó có nghĩa là ngưỡng 50% là 1024 lần xác nhận. Nhưng vì đây là một tham số thống kê, không có gì đảm bảo rằng những va chạm như vậy không xảy ra sớm hơn.
Rudi

2
Vì hàm băm dựa trên nội dung, nên vẫn có khả năng hai xác nhận có cùng tiền tố băm không, không chắc chắn. Tại 65536 cam kết rất có thể hai người sẽ có cùng một tiền tố bốn ký tự, nhưng vẫn không chắc chắn. Bên cạnh đó, hàm băm đầy đủ chưa có xung đột, nhưng git đang làm việc với nó :) stackoverflow.com/questions/3475648/ hiệu
goodeye

6

Đây là những gì tôi đã làm trong makefile của mình dựa trên các giải pháp khác. Lưu ý không chỉ cung cấp cho mã của bạn một số sửa đổi, nó còn nối thêm hàm băm cho phép bạn tạo lại bản phát hành.

# Set the source control revision similar to subversion to use in 'c'
# files as a define.
# You must build in the master branch otherwise the build branch will
# be prepended to the revision and/or "dirty" appended. This is to
# clearly ID developer builds.
REPO_REVISION_:=$(shell git rev-list HEAD --count)
BUILD_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD)
BUILD_REV_ID:=$(shell git rev-parse HEAD)
BUILD_REV_ID_SHORT:=$(shell git describe --long --tags --dirty --always)
ifeq ($(BUILD_BRANCH), master)
REPO_REVISION:=$(REPO_REVISION_)_g$(BUILD_REV_ID_SHORT)
else
REPO_REVISION:=$(BUILD_BRANCH)_$(REPO_REVISION_)_r$(BUILD_REV_ID_SHORT)
endif
export REPO_REVISION
export BUILD_BRANCH
export BUILD_REV_ID

3
Có vẻ như cách an toàn nhất để sử dụng git-describeđể tránh lỗi, là cách git describe --always --dirty --long --tagsnào hiệu quả trong mọi trường hợp tôi có thể nghĩ ra.
MarkHu

5

Vấn đề với việc sử dụng băm git làm số bản dựng là nó không tăng đơn điệu. OSGi đề xuất sử dụng dấu thời gian cho số bản dựng. Có vẻ như số lượng cam kết cho chi nhánh có thể được sử dụng thay cho số lần lật đổ hoặc thay đổi lực lượng.


5

Tôi đã viết một số tiện ích PowerShell để truy xuất thông tin phiên bản từ Git và đơn giản hóa việc gắn thẻ

các chức năng: Get-LastVersion, Get-Revision, Get-NextMajorVersion, Get-NextMinorVersion, TagNextMajorVersion, TagNextMinorVersion:

# Returns the last version by analysing existing tags,
# assumes an initial tag is present, and
# assumes tags are named v{major}.{minor}.[{revision}]
#
function Get-LastVersion(){
  $lastTagCommit = git rev-list --tags --max-count=1
  $lastTag = git describe --tags $lastTagCommit
  $tagPrefix = "v"
  $versionString = $lastTag -replace "$tagPrefix", ""
  Write-Host -NoNewline "last tagged commit "
  Write-Host -NoNewline -ForegroundColor "yellow" $lastTag
  Write-Host -NoNewline " revision "
  Write-Host -ForegroundColor "yellow" "$lastTagCommit"
  [reflection.assembly]::LoadWithPartialName("System.Version")

  $version = New-Object System.Version($versionString)
  return $version;
}

# Returns current revision by counting the number of commits to HEAD
function Get-Revision(){
   $lastTagCommit = git rev-list HEAD
   $revs  = git rev-list $lastTagCommit |  Measure-Object -Line
   return $revs.Lines
}

# Returns the next major version {major}.{minor}.{revision}
function Get-NextMajorVersion(){
    $version = Get-LastVersion;
    [reflection.assembly]::LoadWithPartialName("System.Version")
    [int] $major = $version.Major+1;
    $rev = Get-Revision
    $nextMajor = New-Object System.Version($major, 0, $rev);
    return $nextMajor;
}

# Returns the next minor version {major}.{minor}.{revision}
function Get-NextMinorVersion(){
    $version = Get-LastVersion;
    [reflection.assembly]::LoadWithPartialName("System.Version")
    [int] $minor = $version.Minor+1;
    $rev = Get-Revision
    $next = New-Object System.Version($version.Major, $minor, $rev);
    return $next;
}

# Creates a tag with the next minor version
function TagNextMinorVersion($tagMessage){
    $version = Get-NextMinorVersion;
    $tagName = "v{0}" -f "$version".Trim();
    Write-Host -NoNewline "Tagging next minor version to ";
    Write-Host -ForegroundColor DarkYellow "$tagName";
    git tag -a $tagName -m $tagMessage
}

# Creates a tag with the next major version (minor version starts again at 0)
function TagNextMajorVersion($tagMessage){
    $version = Get-NextMajorVersion;
    $tagName = "v{0}" -f "$version".Trim();
    Write-Host -NoNewline "Tagging next majo version to ";
    Write-Host -ForegroundColor DarkYellow "$tagName";
    git tag -a $tagName -m $tagMessage
}

4

Mỗi cam kết có một hàm băm duy nhất. Khác hơn là không có số sửa đổi trong git. Bạn sẽ phải gắn thẻ cam kết nếu bạn muốn thân thiện với người dùng hơn.


3

Tôi chỉ muốn lưu ý một cách tiếp cận khả thi khác - và đó là bằng cách sử dụng git ghi chú git (1) , tồn tại kể từ phiên bản 1.6.6 ( Lưu ý đến Tự - Git ) (Tôi đang sử dụng gitphiên bản 1.7.9.5).

Về cơ bản, tôi thường git svnsao chép một kho lưu trữ SVN với lịch sử tuyến tính (không có bố cục tiêu chuẩn, không có chi nhánh, không có thẻ) và tôi muốn so sánh các số sửa đổi trong gitkho lưu trữ nhân bản . Bản sao git này không có thẻ theo mặc định, vì vậy tôi không thể sử dụng git describe. Chiến lược ở đây có thể sẽ chỉ hoạt động đối với lịch sử tuyến tính - không chắc nó sẽ diễn ra như thế nào với sự hợp nhất, v.v.; nhưng đây là chiến lược cơ bản:

  • Yêu cầu git rev-listdanh sách tất cả lịch sử cam kết
    • Do rev-listtheo mặc định theo "thứ tự thời gian đảo ngược", chúng tôi sẽ sử dụng công --reversetắc của nó để nhận danh sách các cam kết được sắp xếp theo thứ tự cũ nhất trước
  • Sử dụng bashvỏ để
    • tăng một biến truy cập trên mỗi cam kết như một bộ đếm sửa đổi,
    • tạo và thêm một ghi chú git "tạm thời" cho mỗi lần xác nhận
  • Sau đó, duyệt nhật ký bằng cách sử dụng git logvới --notes, cũng sẽ kết xuất ghi chú của cam kết, trong trường hợp này sẽ là "số sửa đổi"
  • Khi hoàn tất, hãy xóa các ghi chú tạm thời ( NB: Tôi không chắc những ghi chú này có được cam kết hay không; chúng không thực sự hiển thị tronggit status )

Trước tiên, hãy lưu ý rằng gitcó một vị trí ghi chú mặc định - nhưng bạn cũng có thể chỉ định ref(erence) cho ghi chú - sẽ lưu trữ chúng trong một thư mục khác bên dưới .git; ví dụ, trong khi trong gitthư mục repo, bạn có thể gọi git notes get-refđể xem thư mục nào sẽ là:

$ git notes get-ref
refs/notes/commits
$ git notes --ref=whatever get-ref
refs/notes/whatever

Điều cần lưu ý là nếu bạn notes addvới a --ref, sau đó bạn cũng phải sử dụng lại tham chiếu đó - nếu không bạn có thể gặp lỗi như " Không tìm thấy ghi chú nào cho đối tượng XXX ... ".

Trong ví dụ này, tôi đã chọn gọi các refghi chú là "linrev" (để sửa đổi tuyến tính) - điều này cũng có nghĩa là không có khả năng thủ tục sẽ can thiệp vào các ghi chú đã có. Tôi cũng đang sử dụng công --git-dirtắc, vì là một người gitmới, tôi đã gặp một số vấn đề trong việc hiểu nó - vì vậy tôi muốn "nhớ lại sau" :); và tôi cũng sử dụng --no-pagerđể ngăn chặn sinh sản lesskhi sử dụng git log.

Vì vậy, giả sử bạn đang ở trong một thư mục, với thư mục con myrepo_gitgitkho lưu trữ; người ta có thể làm:

### check for already existing notes:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.

### iterate through rev-list three, oldest first,
### create a cmdline adding a revision count as note to each revision

$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
  TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
  TCMD="$TCMD add $ih -m \"(r$((++ix)))\""; \
  echo "$TCMD"; \
  eval "$TCMD"; \
done

# git --git-dir=./myrepo_git/.git notes --ref linrev add 6886bbb7be18e63fc4be68ba41917b48f02e09d7 -m "(r1)"
# git --git-dir=./myrepo_git/.git notes --ref linrev add f34910dbeeee33a40806d29dd956062d6ab3ad97 -m "(r2)"
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev add 04051f98ece25cff67e62d13c548dacbee6c1e33 -m "(r15)"

### check status - adding notes seem to not affect it:

$ cd myrepo_git/
$ git status
# # On branch master
# nothing to commit (working directory clean)
$ cd ../

### check notes again:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# (r15)

### note is saved - now let's issue a `git log` command, using a format string and notes:

$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)
# 77f3902: _user_: Sun Apr 21 18:29:00 2013 +0000:  >>test message 14<< (r14)
# ...
# 6886bbb: _user_: Sun Apr 21 17:11:52 2013 +0000:  >>initial test message 1<< (r1)

### test git log with range:

$ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
# 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)

### erase notes - again must iterate through rev-list

$ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \
  TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \
  TCMD="$TCMD remove $ih"; \
  echo "$TCMD"; \
  eval "$TCMD"; \
done
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# Removing note for object 6886bbb7be18e63fc4be68ba41917b48f02e09d7
# git --git-dir=./myrepo_git/.git notes --ref linrev remove f34910dbeeee33a40806d29dd956062d6ab3ad97
# Removing note for object f34910dbeeee33a40806d29dd956062d6ab3ad97
# ...
# git --git-dir=./myrepo_git/.git notes --ref linrev remove 04051f98ece25cff67e62d13c548dacbee6c1e33
# Removing note for object 04051f98ece25cff67e62d13c548dacbee6c1e33

### check notes again:

$ git --git-dir=./myrepo_git/.git notes show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.
$ git --git-dir=./myrepo_git/.git notes --ref=linrev show
# error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33.

Vì vậy, ít nhất trong trường hợp cụ thể của tôi về lịch sử tuyến tính hoàn toàn không có nhánh, các số sửa đổi dường như khớp với cách tiếp cận này - và ngoài ra, dường như cách tiếp cận này sẽ cho phép sử dụng git logvới phạm vi sửa đổi, trong khi vẫn nhận được số sửa đổi phù hợp - YMMV với một bối cảnh khác, mặc dù ...

Hy vọng điều này sẽ giúp ai đó,
Chúc mừng!


EDIT: Ok, ở đây dễ dàng hơn một chút, với các gitbí danh cho các vòng lặp ở trên, được gọi setlinrevunsetlinrev; khi trong thư mục kho git của bạn, hãy làm ( Lưu ý bashthoát khó chịu , xem thêm # 16136745 - Thêm bí danh Git có chứa dấu chấm phẩy ):

cat >> .git/config <<"EOF"
[alias]
  setlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
      TCMD=\"git notes --ref linrev\"; \n\
      TCMD=\"$TCMD add $ih -m \\\"(r\\$((++ix)))\\\"\"; \n\
      #echo \"$TCMD\"; \n\
      eval \"$TCMD\"; \n\
    done; \n\
    echo \"Linear revision notes are set.\" '"

  unsetlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\
      TCMD=\"git notes --ref linrev\"; \n\
      TCMD=\"$TCMD remove $ih\"; \n\
      #echo \"$TCMD\"; \n\
      eval \"$TCMD 2>/dev/null\"; \n\
    done; \n\
    echo \"Linear revision notes are unset.\" '"
EOF

... vì vậy bạn chỉ có thể gọi git setlinrevtrước khi thử ghi nhật ký liên quan đến ghi chú sửa đổi tuyến tính; và git unsetlinrevđể xóa những ghi chú khi bạn hoàn thành; một ví dụ từ bên trong thư mục git repo:

$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 <<

$ git setlinrev
Linear revision notes are set.
$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 << (r15)
$ git unsetlinrev
Linear revision notes are unset.

$ git log --notes=linrev --format=format:"%h: %an: %ad:  >>%s<< %N" HEAD^..HEAD
04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000:  >>test message 15 <<

Thời gian cần thiết để hoàn thành các bí danh này, sẽ phụ thuộc vào kích thước của lịch sử kho lưu trữ.


2

Đối với những người có quy trình xây dựng Ant , bạn có thể tạo số phiên bản cho dự án trên git với mục tiêu này:

<target name="generate-version">

    <exec executable="git" outputproperty="version.revisions">
        <arg value="log"/>
        <arg value="--oneline"/>
    </exec>

    <resourcecount property="version.revision" count="0" when="eq">
        <tokens>
            <concat>
                <filterchain>
                    <tokenfilter>
                        <stringtokenizer delims="\r" />
                    </tokenfilter>
                </filterchain>
            <propertyresource name="version.revisions" />
            </concat>
        </tokens>
    </resourcecount>
    <echo>Revision : ${version.revision}</echo>

    <exec executable="git" outputproperty="version.hash">
        <arg value="rev-parse"/>
        <arg value="--short"/>
        <arg value="HEAD"/>
    </exec>
    <echo>Hash : ${version.hash}</echo>


    <exec executable="git" outputproperty="version.branch">
        <arg value="rev-parse"/>
        <arg value="--abbrev-ref"/>
        <arg value="HEAD"/>
    </exec>
    <echo>Branch : ${version.branch}</echo>

    <exec executable="git" outputproperty="version.diff">
        <arg value="diff"/>
    </exec>

    <condition property="version.dirty" value="" else="-dirty">
        <equals arg1="${version.diff}" arg2=""/>
    </condition>

    <tstamp>
        <format property="version.date" pattern="yyyy-mm-dd.HH:mm:ss" locale="en,US"/>
    </tstamp>
    <echo>Date : ${version.date}</echo>

    <property name="version" value="${version.revision}.${version.hash}.${version.branch}${version.dirty}.${version.date}" />

    <echo>Version : ${version}</echo>

    <echo file="version.properties" append="false">version = ${version}</echo>

</target>

Kết quả trông như thế này:

generate-version:
    [echo] Generate version
    [echo] Revision : 47
    [echo] Hash : 2af0b99
    [echo] Branch : master
    [echo] Date : 2015-04-20.15:04:03
    [echo] Version : 47.2af0b99.master-dirty.2015-04-20.15:04:03

Cờ bẩn ở đây khi bạn có (các) tệp không được cam kết khi bạn tạo số phiên bản. Bởi vì thông thường, khi bạn xây dựng / đóng gói ứng dụng của mình, mọi sửa đổi mã phải có trong kho lưu trữ.


1

Cùng với id SHA-1 của cam kết, ngày và giờ của thời gian máy chủ có giúp được gì không?

Một cái gì đó như thế này:

cam kết xảy ra lúc 11:30:25 ngày 19 tháng 8 năm 2013 sẽ hiển thị là 6886bbb7be18e63fc4be68ba41917b48f02e09d7_19aug2013_113025


1

Từ hướng dẫn sử dụng Git, các thẻ là một câu trả lời tuyệt vời cho vấn đề này:

Tạo một thẻ chú thích trong Git rất đơn giản. Cách dễ nhất là chỉ định -a khi bạn chạy lệnh thẻ:

$ git tag -a v1.4 -m 'my version 1.4'

$ git tag
v0.1
v1.3
v1.4

Kiểm tra cơ bản 2.6 Git - Gắn thẻ


Quá xấu bạn phải nhảy qua hoops để thay đổi giá trị mặc định:By default, the git push command doesn’t transfer tags to remote servers.
MarkHu

1

Chúng tôi đang sử dụng lệnh này để nhận phiên bản và sửa đổi từ git:

git describe --always --tags --dirty

Nó trở lại

  • cam kết băm như sửa đổi khi không sử dụng gắn thẻ (ví dụ: gcc7b71f )
  • tên thẻ là phiên bản khi trên thẻ (ví dụ: v2.1.0 được sử dụng để phát hành)
  • tên thẻ, số sửa đổi kể từ thẻ cuối cùng và cam kết băm khi sau thẻ (ví dụ: v5.3.0-88-gcc7b71f )
  • tương tự như trên cộng với thẻ "bẩn" nếu cây làm việc có sửa đổi cục bộ (ví dụ v5.3.0-88-gcc7b71f-dirty)

Xem thêm: https://www.git-scm.com/docs/git-describe#Documentation/git-describe.txt


0

Đăng sự kiện xây dựng cho Visual Studio

echo  >RevisionNumber.cs static class Git { public static int RevisionNumber =
git  >>RevisionNumber.cs rev-list --count HEAD
echo >>RevisionNumber.cs ; }

-1

Cân nhắc sử dụng

git-rev-label

Cung cấp thông tin về sửa đổi kho Git theo định dạng như thế nào master-c73-gabc6bec. Có thể điền chuỗi mẫu hoặc tệp với các biến môi trường và thông tin từ Git. Hữu ích để cung cấp thông tin về phiên bản của chương trình: chi nhánh, thẻ, cam kết băm, cam kết đếm, trạng thái bẩn, ngày và giờ. Một trong những điều hữu ích nhất là số lượng cam kết, không tính đến các chi nhánh được sáp nhập - chỉ có cha mẹ đầu tiên.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.