Git เทียบเท่ากับหมายเลขการแก้ไขคืออะไร


244

เราใช้ SVN ในที่ทำงาน แต่สำหรับโครงการส่วนตัวของฉันฉันตัดสินใจใช้ Git ดังนั้นผมจึงติดตั้ง Git เมื่อวานนี้และฉันสงสัยว่าเป็นจำนวนการแก้ไขเทียบเท่าใน Git

สมมติว่าเราทำงานกับเวอร์ชัน 3.0.8 และทุกการแก้ไขข้อบกพร่องมีหมายเลขการแก้ไขของตัวเองที่เราสามารถใช้เมื่อเราพูดถึงการแก้ไขข้อผิดพลาดนี้ ดังนั้นหากฉันติดแท็กรหัสใน Git ถึง 3.0.8 ฉันสามารถใช้อะไรเป็นหมายเลขการแก้ไขหรือการระบุรายละเอียดอื่น ๆ ฉันพบว่าแฮชไม่เป็นมิตรต่อผู้ใช้สำหรับมนุษย์


มีความเป็นไปได้ที่ซ้ำกันของการนับคอมมิท?
Laurence Gonsalves

มีบทความสำหรับหนึ่งในวิธีแก้ปัญหาที่เป็นไปได้ มันอาจดูค่อนข้างหนัก แต่ถูกรวมเข้ากับเอาต์พุต "git log" และไม่ต้องการคำสั่งเพิ่มเติมอื่นนอกจาก "git push / pull / fetch"
Dmitry Pavlenko

โชคร้ายบทความที่เชื่อมโยงจาก @DmitryPavlenko อยู่ในโดเมนที่ตายแล้ว: gitsvn.x10.mx หากไม่มีข้อบ่งชี้ของเรื่องมันจะยากสำหรับทุกคนที่จะหาที่อื่น
Michael Donohue

หมายเหตุ: ไม่จำเป็นต้องใช้ตัวย่ออีกต่อไปในการอธิบาย git: ดูstackoverflow.com/a/41308073/6309
VonC

1
ไม่ Laurence Gonsalves นี่ไม่ใช่สิ่งที่ซ้ำกันของ "วิธีการรับค่าคอมมิท?" - นี่เป็นเรื่องเกี่ยวกับหมายเลขเวอร์ชันและแม้ว่าจำนวนการคอมมิทชั่นสามารถเล่นเพื่อดูเล็กน้อยได้ - แฮชเวอร์ชันนั้นแตกต่างจากการส่งคอมมิชชัน :-)
David Svarrer

คำตอบ:


149

ข่าวดีหรือข่าวร้ายสำหรับคุณนั่นคือหมายเลขการแก้ไข ฉันยังมีปัญหากับสิ่งนี้เมื่อฉันเปลี่ยนจาก SVN เป็นคอมไพล์

คุณสามารถใช้ "การแท็ก" ในคอมไพล์เพื่อติดแท็กการแก้ไขบางอย่างเป็น "รีลีส" สำหรับเวอร์ชันที่ระบุทำให้ง่ายต่อการอ้างถึงการแก้ไขนั้น ลองดูโพสต์บล็อกนี้

สิ่งสำคัญที่ต้องเข้าใจคือคอมไพล์ไม่สามารถมีหมายเลขการแก้ไข - คิดเกี่ยวกับลักษณะการกระจายอำนาจ หากผู้ใช้ A และ B ทั้งสองส่งมอบให้กับที่เก็บข้อมูลในพื้นที่ของตนพวกเขาจะสามารถกำหนดหมายเลขการแก้ไขตามลำดับได้อย่างไร A ไม่มีความรู้เกี่ยวกับ B ก่อนที่พวกเขาจะผลัก / ดึงการเปลี่ยนแปลงของกันและกัน

สิ่งที่จะต้องดูก็คือการแยกย่อยสำหรับการแก้ไขข้อบกพร่องแบบง่าย ๆ :

เริ่มต้นด้วยการเปิดตัว: 3.0.8 จากนั้นหลังจากปล่อยให้ทำดังนี้

git branch bugfixes308

สิ่งนี้จะสร้างสาขาสำหรับการแก้ไขข้อบกพร่อง ชำระเงินที่สาขา:

git checkout bugfixes308

ตอนนี้ทำการแก้ไขข้อผิดพลาดที่คุณต้องการ

git commit -a

มุ่งมั่นพวกเขาและเปลี่ยนกลับไปที่สาขาหลัก:

git checkout master

จากนั้นดึงการเปลี่ยนแปลงเหล่านั้นจากสาขาอื่น:

git merge bugfixes308

ด้วยวิธีนี้คุณมีสาขาแก้ไขบั๊กเฉพาะแยกต่างหาก แต่คุณยังคงดึงการแก้ไขบั๊กมาไว้ในลำต้นหลักของคุณ


11
ฉันเข้าใจว่าแฮชเป็นหมายเลขการแก้ไข แต่ฉันหวังว่ามันไม่ใช่ :-))) ขอบคุณสำหรับคำอธิบายที่ดีมากและสำหรับคำแนะนำในการจัดการกับมัน
Radek

3
ไม่เป็นไร ฉันรู้สึกหงุดหงิดมากกับ git เมื่อฉันหยิบมันขึ้นมาจาก SVN แต่ตอนนี้ฉันแกว่งไปทางอื่น ...
makdad

4
นอกจากนี้ยังไม่นานมานี้ตั้งแต่ฉันโพสต์สิ่งนี้ แต่โปรดจำไว้ว่าคุณสามารถทำ "git checkout -b new_branch_name" เพื่อทำ "git branch foo" และ "git checkout foo" เป็นหนึ่งซับ
makdad

1
ฉันถูกต้องหรือไม่ว่าแฮชนั้นเป็น "จริง" แฮชและไม่ได้เรียงตามลำดับจากระยะไกล ดังนั้นที่สำคัญถ้าฐานข้อมูลข้อผิดพลาดบอกว่าfixed in 547cc3e..c4b2ebaและคุณมีการแก้ไขอื่น ๆ คุณไม่มีความคิดว่ารหัสของคุณควรจะมีการแก้ไขหรือไม่! แน่นอนว่า gits ที่ git-central นั้นมีทางออกสำหรับสิ่งนี้?!?!
Olie

3
ใน SVN ความจริงที่ว่าข้อผิดพลาดได้รับการแก้ไขใน r42 ไม่ได้บอกคุณว่ามันถูกแก้ไขใน r43 ทันทีที่คุณใช้กิ่งไม้จริงหรือไม่
Matthieu Moy

186

ด้วย Git ที่ทันสมัย ​​(1.8.3.4 ในกรณีของฉัน) และไม่ใช้สาขาคุณสามารถทำได้:

$ git rev-list --count HEAD
68

22
ลองใช้git rev-list --count --first-parent HEAD
Flimm

8
ด้วยข้อมูลนี้ (หมายเลข 68) มีวิธีการตรวจสอบการแก้ไขสำหรับการรับรหัสอีกครั้งหรือไม่ สมมติว่า "การแก้ไข 68" ถูกปล่อยสู่สภาพแวดล้อมการทดสอบการพัฒนาดำเนินต่อไปและต่อมาผู้พัฒนาจำเป็นต้องได้รับ "การแก้ไข 68" อีกครั้งจากแหล่งควบคุม เขาจะกำหนดเป้าหมายเฉพาะรุ่นเพื่อโคลนได้อย่างไร หรือฉันขาดอะไรบางอย่างเกี่ยวกับ Git ที่ทำให้สิ่งนี้ไม่จำเป็น?
David

9
โปรดทราบว่าโซลูชันนี้จะให้ผลลัพธ์ที่แตกต่างกันสำหรับนักพัฒนาที่แตกต่างกัน นอกจากนี้การคำนวณย้อนกลับจาก "นับ" ถึงการกระทำจะให้ผลตอบแทนที่แตกต่างกันสำหรับนักพัฒนาที่แตกต่างกัน !! นี่เป็นเพราะลักษณะการกระจายตัวของ Git และการกระทำที่เกิดขึ้นในที่เก็บข้อมูลที่แตกต่างกันในช่วงเวลาเดียวกัน แต่อาจไม่สามารถนับได้git rev-list --count HEADขึ้นอยู่กับเมื่อทำการกดและดึงครั้งล่าสุด
เจสัน

2
@ Jason ความเห็นของเดวิดเกี่ยวกับการเพิ่ม--first-parentความกังวลของคุณหรือไม่? ฉันเกลียดที่จะหลีกเลี่ยงวิธีแก้ปัญหาที่ดูง่ายที่สุดเพราะมีกรณีขอบที่หายากหากมีวิธีแก้ปัญหาที่เรียบง่ายไม่แพ้กันหรือวิธีที่จะทำให้มันแข็งแกร่งขึ้น
MarkHu

4
@ MarkHu --first-parentช่วย ตราบใดที่ไม่มีการรีบูตแล้วและมีการใช้สาขาเดียวกันสำหรับการเผยแพร่เสมอ (และการคำนวณหมายเลขรีลีสนี้แน่นอน) ฉันคิดว่านี่สามารถใช้งานได้ แม้ว่าฉันยังคงไม่แน่ใจว่ามันจะระบุความมุ่งมั่นที่ไม่ซ้ำกันที่ปล่อยมาจาก มีหลายสิ่งหลายอย่างที่ผิดพลาดได้ที่นี่ ... แต่ในขณะนี้ฉันไม่สามารถนึกถึงบางสิ่งที่จะทำลายสิ่งนี้ได้อย่างแน่นอน git describeวิธีที่กล่าวถึงในคำตอบอื่นเป็นวิธีที่จะไป สร้างแท็กถ้าคุณต้องการให้คนอ่านได้
เจสัน

104

git describeคำสั่งสร้างชื่ออ่านเล็กน้อยของมนุษย์มากขึ้นว่าหมายถึงการกระทำที่เฉพาะเจาะจง ตัวอย่างเช่นจากเอกสาร:

ด้วยบางอย่างเช่นต้นไม้ปัจจุบัน git.git ฉันได้รับ:

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

นั่นคือหัวปัจจุบันของสาขา "แม่" ของฉันมีพื้นฐานอยู่ที่ v1.0.4 แต่เนื่องจากมันมีความมุ่งมั่นเพียงไม่กี่คำอธิบายจึงได้เพิ่มจำนวนการกระทำเพิ่มเติม ("14") และชื่อวัตถุแบบย่อสำหรับการส่งมอบ ตัวเอง ("2414721") ในตอนท้าย

ตราบใดที่คุณใช้แท็กที่ตั้งชื่ออย่างสมเหตุสมผลเพื่อติดแท็กรีลีสเฉพาะสิ่งนี้สามารถพิจารณาได้ว่าเทียบเท่ากับ "หมายเลขการแก้ไข" ของ SVN


7
ฉันแค่อยากจะทราบว่ามันใช้งานได้เฉพาะในกรณีที่gitพื้นที่เก็บข้อมูลของคุณมีแท็กแล้ว หากไม่เป็นเช่นนั้นคุณอาจได้รับการอธิบายคอมไพล์ล้มเหลวด้วย "ร้ายแรง: ไม่พบชื่อไม่สามารถอธิบายอะไรได้" - สแต็คล้น ; หมายความว่าคุณต้องตั้งค่าแท็กด้วยตัวเอง
sdaau

14
@sdaau: หากคุณใช้สิ่งนี้ในสคริปต์หรือบางสิ่งบางอย่างและไม่ต้องการgit describeล้มเหลวให้ใช้git describe --alwaysตัวเลือก
Greg Hewgill

สามารถใช้ผลลัพธ์ของgit describeการค้นหาแหล่งที่มากระทำได้หรือไม่? การนับด้วยตนเองในบันทึกสั้น ๆ ฉันหมายถึง
Lii

@Lii: คุณหมายถึงอะไรโดย "แหล่งที่มากระทำ" ทั้งแท็กที่ใกล้ที่สุด ( v1.0.4) และกระทำล่าสุด ( 2414721) เป็นส่วนหนึ่งของ git อธิบายเอาท์พุท
Greg Hewgill

@ GregHewgill: ใช่ขอบคุณเมื่อฉันถามคำถามฉันไม่ได้ตระหนักว่า"ชื่อวัตถุย่อ"เป็นค่าที่สามารถใช้เพื่อระบุการกระทำ นั่นยอดเยี่ยม!
Lii

67

โปสเตอร์อื่น ๆ ถูกต้องไม่มี "หมายเลขการแก้ไข"

ฉันคิดว่าวิธีที่ดีที่สุดคือการใช้แท็กสำหรับ "เผยแพร่"!

แต่ฉันใช้ข้อมูลต่อไปนี้เพื่อแก้ไขตัวเลขปลอม (เพื่อให้ลูกค้าเห็นการแก้ไขและความคืบหน้าเนื่องจากพวกเขาต้องการให้มีการแก้ไขเพิ่มขึ้นจาก git เหมือนกับที่ใช้ในการโค่นล้ม)

แสดง "การแก้ไขปัจจุบัน" ของ "HEAD" เป็นการจำลองโดยใช้สิ่งนี้:

git rev-list HEAD | wc -l

แต่ถ้าลูกค้าบอกฉันว่ามีข้อผิดพลาดใน "การแก้ไข" 1302

สำหรับสิ่งนี้ฉันได้เพิ่มสิ่งต่อไปนี้ในส่วน [alias] ของ ~ / .gitconfig ของฉัน:

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

ใช้git show-rev-number 1302จะพิมพ์กัญชาสำหรับ "การแก้ไข" :)

ฉันสร้างบล็อกโพสต์ (ภาษาเยอรมัน)เกี่ยวกับ "เทคนิค" เมื่อไม่นานมานี้


@Radek - "บางครั้งจำเป็นต้องรู้ว่า 'code change = commit' แก้ไขอะไรบางอย่าง" - แล้วgit bisect(ลิงก์)เป็นเครื่องมือที่เหมาะสมในการระบุสิ่งที่เปลี่ยนแปลงเมื่อใคร
ไมเคิล

@ Radek ใช่มันเป็นจำนวนที่เพิ่มขึ้นเรื่อย ๆ เพียงนับการแก้ไขที่คุณเช็คอินบน HEAD ดังนั้นการกระทำทุกอย่างเป็นการแก้ไขใหม่ สิ่งนี้จะไม่ทำงานสำหรับสาขาต่าง ๆ
OderWat

1
ฉันชอบทางออกของคุณ โปรดสังเกตว่าคุณสามารถทำให้มันง่ายขึ้น: show-rev-number =! sh -c 'git rev-list - REVerse HEAD | awk NR == $ 0 '
avner

@avner ขอขอบคุณ! ผมไม่ได้ใช้จำนวนมาก awk ในชีวิตของฉันอย่างเห็นได้ชัด :)
OderWat

3
ฉันต้องใช้git rev-list --reverse HEAD | awk "{ print NR }" | tail -n 1
Gerry

27

Git ไม่มีแนวคิดเดียวกันกับหมายเลขการแก้ไขเช่นเดียวกับการโค่นล้ม แต่ละสแน็ปช็อตที่กำหนดที่ทำด้วยการส่งข้อมูลจะถูกติดแท็กโดยการตรวจสอบ SHA1 ทำไม? มีปัญหาหลายอย่างกับ revno ที่กำลังทำงานอยู่ในระบบควบคุมเวอร์ชันแบบกระจาย:

ประการแรกเนื่องจากการพัฒนาไม่ได้เป็นเส้นตรงเลยการแนบหมายเลขค่อนข้างยากที่จะแก้ปัญหาในลักษณะที่จะตอบสนองความต้องการของคุณในฐานะโปรแกรมเมอร์ การพยายามแก้ไขด้วยการเพิ่มตัวเลขอาจเป็นปัญหาได้อย่างรวดเร็วเมื่อตัวเลขไม่ทำงานตามที่คุณคาดไว้

ประการที่สองหมายเลขการแก้ไขอาจถูกสร้างขึ้นในเครื่องที่แตกต่างกัน สิ่งนี้ทำให้การซิงโครไนซ์ตัวเลขทำได้ยากขึ้นโดยเฉพาะอย่างยิ่งเนื่องจากการเชื่อมต่อเป็นแบบทางเดียว คุณอาจไม่สามารถเข้าถึงเครื่องทั้งหมดที่มีที่เก็บ

ประการที่สามในคอมไพล์ซึ่งเป็นผู้บุกเบิกโดยระบบ OpenCM ที่หมดอายุแล้วในตอนนี้ตัวตนของคอมมิท (การคอมมิทคืออะไร) เทียบเท่ากับชื่อของมัน(the SHA id) นี้ตั้งชื่อ = ตัวตนแนวคิดมีความแข็งแรงมาก เมื่อคุณนั่งกับชื่อการกระทำในมือมันก็จะระบุการกระทำในลักษณะที่ไม่อาจลืมได้ ในทางกลับกันนี้ช่วยให้คุณตรวจสอบการกระทำทั้งหมดของคุณกลับไปเป็นคนแรกที่เริ่มต้นสำหรับความเสียหายด้วยgit fsckคำสั่ง

ตอนนี้เนื่องจากเรามี DAG (Directed Acyclic Graph) ของการแก้ไขและสิ่งเหล่านี้เป็นต้นไม้ปัจจุบันเราต้องการเครื่องมือบางอย่างในการแก้ปัญหาของคุณ : เราจะแยกแยะรุ่นต่าง ๆ ได้อย่างไร ขั้นแรกคุณสามารถละเว้นส่วนหนึ่งของแฮชได้หากคำนำหน้าที่ระบุ1516bdพูดระบุการกระทำของคุณโดยเฉพาะ แต่นี่ก็เป็นการวางแผนที่ค่อนข้าง เคล็ดลับคือการใช้แท็กและหรือสาขาแทน แท็กหรือสาขาคล้ายกับ "แท่งสีเหลืองมันหมายเหตุ" คุณแนบไปกับการกระทำ SHA1-id ที่กำหนด โดยพื้นฐานแล้วแท็กนั้นหมายถึงว่าจะไม่เคลื่อนไหวในขณะที่สาขาจะเคลื่อนที่เมื่อมีการผูกมัดใหม่เข้ากับ HEAD มีวิธีที่จะอ้างถึงการกระทำรอบแท็กหรือสาขาให้ดูที่หน้าคนของ git-rev-parse

โดยปกติหากคุณต้องการทำงานกับโค้ดเฉพาะชิ้นส่วนนั้นจะอยู่ระหว่างการเปลี่ยนแปลงและควรเป็นสาขาที่มีชื่อหัวข้อพูด การสร้างสาขาจำนวนมาก (20-30 ต่อโปรแกรมเมอร์ไม่เคยได้ยินมาก่อนมีการตีพิมพ์ 4-5 รายการเพื่อให้คนอื่นทำงาน) เป็นเคล็ดลับสำหรับคอมไพล์ที่มีประสิทธิภาพ งานทุกชิ้นควรเริ่มต้นเป็นสาขาของตนเองจากนั้นจะรวมเข้าด้วยกันเมื่อมีการทดสอบ สาขาที่ไม่ได้เผยแพร่สามารถเขียนใหม่ทั้งหมดและเป็นส่วนหนึ่งของการทำลายประวัติศาสตร์นี้เป็นพลังของคอมไพล์

เมื่อการเปลี่ยนแปลงได้รับการยอมรับในระดับปริญญาโทมันจะค่อนข้างค้างและกลายเป็นโบราณคดี ณ จุดนี้คุณสามารถติดแท็กได้ แต่บ่อยครั้งที่การอ้างอิงถึงการกระทำที่ทำไว้ในตัวติดตามบั๊กหรือตัวติดตามปัญหาผ่านทางผลรวม sha1 แท็กมักจะถูกสงวนไว้สำหรับการกระแทกเวอร์ชันและคะแนนสาขาสำหรับการบำรุงรักษาสาขา (สำหรับเวอร์ชันเก่า)


18

หากคุณสนใจฉันจัดการหมายเลขเวอร์ชันโดยอัตโนมัติจาก git infos ที่นี่ภายใต้รูปแบบ

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

โดยที่ build คือจำนวนการคอมมิตทั้งหมด Makefileคุณจะเห็นรหัสที่น่าสนใจใน นี่คือส่วนที่เกี่ยวข้องในการเข้าถึงส่วนต่าง ๆ ของหมายเลขรุ่น:

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

ฟังก์ชั่นทุบตี:

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}
}

แสดงผลเหมือน

$ git_rev
2:0f8e14e:20130220

นั่นคือ

commit_count:last_abbrev_commit:date_YYmmdd

การเรียงลำดับของสิ่งนั้นอาจมีประโยชน์ แต่ถ้ามีใครสนใจในหมายเลขรุ่นที่เพิ่มขึ้นพวกเขาจะสลับตำแหน่งของเขตข้อมูลเพื่อที่แฮช (ไม่เพิ่มขึ้น) จะมีอายุการใช้งาน
MarkHu

8

กัญชา SHA1 ของการกระทำคือเทียบเท่ากับจำนวนการโค่นล้มการแก้ไข


7
น่าเสียดายที่มีคุณสมบัติแตกต่างกันมากจากหมายเลขการแก้ไข มันค่อนข้างยาวและจะไม่เพิ่มขึ้นซ้ำซากจำเจ เดาว่าเป็นราคาที่ต้องจ่ายสำหรับการจัดจำหน่าย ...
CodesInChaos

1
@CodeInChaos: ฉันรู้ว่าสิ่งที่คุณได้รับ แต่โดยทั่วไปแล้วมันเป็นไปได้ที่จะอ้างถึงคอมไพล์คอมไพล์ด้วยอักขระแฮชโค้ด 6 หรือ 8 ตัวแรกเท่านั้น
Chris Pitman

5
@ Radek: พวกเขาไม่ได้รับประกันว่าจะไม่ซ้ำกัน (แม้ว่าคุณจะพบการชนกันคุณสามารถชนะคนดังจำนวนเล็กน้อย)
Slartibartfast

8
@Radek ตามen.wikipedia.org/wiki/Collision_attackด้วย 4 hash of hash คุณมี 16bit Id ซึ่งหมายความว่าใน repo ที่มี 256 (= 2 ^ (16/2)) มี 50 โอกาส% ที่การคอมมิทสองครั้งมีคำนำหน้าทั้งสี่แบบเดียวกัน (และด้วย 65536 คอมมิทจะถือว่าแน่นอนตั้งแต่นั้นช่วงของรหัส 4-char จะหมดไป) เมื่อคุณเพิ่มอักขระหนึ่งตัวคุณจะมีรหัส 20 บิตซึ่งหมายความว่าเกณฑ์ 50% อยู่ที่ 1024 คอมมิท แต่เนื่องจากนี่เป็นพารามิเตอร์ทางสถิติจึงไม่รับประกันว่าการชนดังกล่าวจะไม่เกิดขึ้นก่อนหน้านี้
ฤดี

2
เนื่องจากแฮชอิงตามเนื้อหาจึงยังคงมีความเป็นไปได้ที่ว่าคอมมิททั้งสองจะมีคำนำหน้าแฮชเดียวกันไม่ใช่ความแน่นอน ที่ 65536 ยอมรับว่าเป็นไปได้มากที่ทั้งสองจะมีคำนำหน้าตัวอักษรสี่ตัวที่เหมือนกัน แต่ก็ยังไม่แน่ใจ นอกจากนี้แฮชแบบเต็มยังไม่มีการชนกัน แต่คอมไพล์กำลังทำงานอยู่ :) stackoverflow.com/questions/3475648/…
goodeye

6

นี่คือสิ่งที่ฉันทำใน makefile ตามโซลูชันอื่น ๆ หมายเหตุสิ่งนี้ไม่เพียงให้รหัสการแก้ไขของคุณ แต่ยังผนวกแฮชที่อนุญาตให้คุณสร้างการเผยแพร่อีกครั้ง

# 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
ดูเหมือนว่าวิธีที่ปลอดภัยที่สุดในการใช้git-describeเพื่อหลีกเลี่ยงข้อผิดพลาดเป็นgit describe --always --dirty --long --tagsสิ่งที่ใช้ได้กับทุกกรณีที่ฉันนึกถึง
MarkHu

5

ปัญหาเกี่ยวกับการใช้แฮช git เป็นหมายเลขบิลด์ก็คือมันไม่ได้เพิ่มความน่าเบื่อ OSGi แนะนำให้ใช้การประทับเวลาสำหรับหมายเลขบิลด์ ดูเหมือนว่าจำนวนของการผูกมัดกับสาขาสามารถใช้แทนการโค่นล้มหรือหมายเลขการเปลี่ยนแปลงที่บังคับได้


5

ฉันได้เขียนโปรแกรมอรรถประโยชน์ PowerShell เพื่อดึงข้อมูลรุ่นจาก Git และทำให้การติดแท็กง่ายขึ้น

ฟังก์ชั่น: 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

การกระทำแต่ละครั้งจะมีแฮชที่เป็นเอกลักษณ์ นอกจากนั้นไม่มีหมายเลขการแก้ไขใน git คุณจะต้องติดแท็กยอมรับว่าคุณต้องการความเป็นมิตรกับผู้ใช้มากขึ้น


3

ฉันต้องการจะบันทึกแนวทางที่เป็นไปได้อีกวิธีหนึ่งและนั่นก็คือการใช้git git-notes (1)ซึ่งมีอยู่ตั้งแต่ v 1.6.6 ( หมายเหตุถึง Self - Git ) (ฉันใช้gitรุ่น 1.7.9.5)

โดยทั่วไปฉันเคยgit svnโคลนที่เก็บ SVN ที่มีประวัติเชิงเส้น (ไม่มีรูปแบบมาตรฐานไม่มีสาขาไม่มีแท็ก) และฉันต้องการเปรียบเทียบหมายเลขการแก้ไขในที่gitเก็บที่โคลน git describeโคลนคอมไพล์นี้ไม่ได้มีแท็กไปโดยปริยายดังนั้นผมจึงไม่สามารถใช้ กลยุทธ์ที่นี่น่าจะใช้ได้เฉพาะกับประวัติเชิงเส้นเท่านั้น - ไม่แน่ใจว่ามันจะเกิดขึ้นได้อย่างไรกับการรวมกัน ฯลฯ แต่นี่คือกลยุทธ์พื้นฐาน:

  • ขอgit rev-listรายชื่อประวัติการกระทำทั้งหมด
    • เนื่องจากrev-listเป็นค่าเริ่มต้นใน "ลำดับเหตุการณ์ย้อนกลับ" เราจะใช้--reverseสวิตช์เพื่อรับรายการการกระทำที่เรียงลำดับตามเก่าที่สุดก่อน
  • ใช้bashเปลือกเพื่อ
    • เพิ่มตัวแปรตัวนับในแต่ละการกระทำเป็นการแก้ไขตัวนับ
    • สร้างและเพิ่มบันทึกชั่วคราว git "ชั่วคราว" สำหรับแต่ละการกระทำ
  • จากนั้นเรียกดูบันทึกโดยใช้git logด้วย--notesซึ่งจะทิ้งบันทึกย่อของการกระทำซึ่งในกรณีนี้จะเป็น "หมายเลขการแก้ไข"
  • เมื่อเสร็จแล้วให้ลบบันทึกชั่วคราว ( หมายเหตุ: ฉันไม่แน่ใจว่าบันทึกเหล่านี้มีความมุ่งมั่นหรือไม่; พวกเขาไม่ได้แสดงจริง ๆgit status )

ก่อนแจ้งให้ทราบว่าgitมีการตั้งค่าเริ่มต้นของการบันทึก - แต่คุณยังสามารถระบุref(erence) สำหรับบันทึก - ซึ่งจะเก็บไว้ในไดเรกทอรีที่แตกต่างกันภายใต้.git; ตัวอย่างเช่นในขณะที่อยู่ในgitโฟลเดอร์ repo คุณสามารถโทรgit notes get-refเพื่อดูไดเรกทอรีที่จะ:

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

สิ่งที่ควรสังเกตคือถ้าคุณnotes addใช้ a --refคุณต้องใช้การอ้างอิงนั้นอีกครั้งหลังจากนั้นมิฉะนั้นคุณอาจได้รับข้อผิดพลาดเช่น " ไม่พบบันทึกย่อสำหรับวัตถุ XXX ... "

สำหรับตัวอย่างนี้ฉันได้เลือกที่จะเรียกrefบันทึกย่อของ "linrev" (สำหรับการแก้ไขเชิงเส้น) - นี่ก็หมายความว่ามันไม่น่าเป็นไปได้ที่กระบวนการจะแทรกแซงกับบันทึกที่มีอยู่แล้ว ฉันยังใช้--git-dirสวิตช์เนื่องจากเป็นgitมือใหม่ฉันมีปัญหาในการทำความเข้าใจ - ดังนั้นฉันต้องการที่จะ "จำไว้เพื่อใช้ในภายหลัง" :); และฉันยังใช้--no-pagerในการวางไข่ของปราบเมื่อใช้lessgit log

ดังนั้นสมมติว่าคุณอยู่ในไดเรกทอรีพร้อมโฟลเดอร์ย่อย myrepo_gitซึ่งเป็นที่gitเก็บ เราสามารถทำได้:

### 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.

อย่างน้อยในกรณีเฉพาะของฉันเกี่ยวกับประวัติเชิงเส้นอย่างสมบูรณ์โดยไม่มีสาขาหมายเลขการแก้ไขดูเหมือนจะตรงกับวิธีการนี้ - และนอกจากนี้ดูเหมือนว่าวิธีนี้จะอนุญาตให้ใช้git logกับช่วงการแก้ไขในขณะที่ยังได้รับหมายเลขการแก้ไขที่ถูกต้อง - YMMV ด้วยบริบทที่แตกต่างแม้ว่า ...

หวังว่านี่จะช่วยใครซักคน
ไชโย!


แก้ไข: ตกลงที่นี่มันง่ายขึ้นเล็กน้อยด้วยgitนามแฝงสำหรับลูปข้างต้นเรียกว่าsetlinrevและunsetlinrev; เมื่ออยู่ในโฟลเดอร์ที่เก็บ git ของคุณให้ทำ ( สังเกตการbashหลบหนีที่น่ารังเกียจดูที่# 16136745 - เพิ่มนามแฝง Git ที่มีเครื่องหมายอัฒภาค ):

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

... เพื่อให้คุณสามารถเรียกใช้git setlinrevก่อนที่จะพยายามบันทึกที่เกี่ยวข้องกับการแก้ไขเชิงเส้นบันทึก; และgit unsetlinrevเพื่อลบบันทึกย่อเหล่านั้นเมื่อคุณทำเสร็จแล้ว; ตัวอย่างจากในไดเรกทอรี 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 <<

เวลาที่ใช้เชลล์เพื่อทำสมนามเหล่านี้ให้เสร็จสมบูรณ์ขึ้นอยู่กับขนาดของประวัติที่เก็บ


2

สำหรับผู้ที่มีกระบวนการสร้างAntคุณสามารถสร้างหมายเลขเวอร์ชันสำหรับโครงการบนคอมไพล์ด้วยเป้าหมายนี้:

<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>

ผลลัพธ์จะเป็นดังนี้:

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

การตั้งค่าสถานะสกปรกอยู่ที่นี่เมื่อคุณไม่มีไฟล์ที่กำหนดไว้เมื่อคุณสร้างหมายเลขเวอร์ชัน เพราะโดยปกติเมื่อคุณสร้าง / แพ็คเกจแอปพลิเคชันของคุณการแก้ไขโค้ดทุกครั้งจะต้องอยู่ในที่เก็บ


1

พร้อมกับรหัส SHA-1 ของการกระทำวันที่และเวลาของเซิร์ฟเวอร์จะช่วยได้หรือไม่

บางสิ่งเช่นนี้

กระทำที่เกิดขึ้นเมื่อ 11:30:25 ในวันที่ 19 สิงหาคม 2013 จะแสดงเป็น 6886bbbb7be18e63fc4be68ba41917b48f02e09d7_19aug2013_113025


1

จากคู่มือ Git แท็กเป็นคำตอบที่ยอดเยี่ยมสำหรับปัญหานี้:

การสร้างแท็กหมายเหตุประกอบใน Git นั้นง่ายมาก วิธีที่ง่ายที่สุดคือการระบุ -a เมื่อคุณรันคำสั่ง tag:

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

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

ตรวจสอบข้อมูลพื้นฐาน 2.6 Git - การติดแท็ก


น่าเสียดายที่คุณต้องข้ามห่วงเพื่อเปลี่ยนค่าเริ่มต้น:By default, the git push command doesn’t transfer tags to remote servers.
MarkHu

1

เรากำลังใช้คำสั่งนี้เพื่อรับรุ่นและการแก้ไขจาก git:

git describe --always --tags --dirty

มันกลับมา

  • กระทำการแฮชเป็นการแก้ไขเมื่อไม่มีการติดแท็ก (เช่น gcc7b71f )
  • ชื่อแท็กเป็นเวอร์ชันเมื่ออยู่บนแท็ก (เช่น v2.1.0ใช้เพื่อเผยแพร่)
  • ชื่อแท็กหมายเลขการแก้ไขตั้งแต่แท็กล่าสุดและส่งแฮชเมื่ออยู่หลังแท็ก (เช่น v5.3.0-88-gcc7b71f )
  • เช่นเดียวกับข้างต้นบวกกับแท็ก "สกปรก" หากต้นไม้ทำงานมีการปรับเปลี่ยนท้องถิ่น (เช่นv5.3.0-88-gcc7b71f-dirty)

ดูเพิ่มเติมที่: https://www.git-scm.com/docs/git-describe#Documentation/git-describe.txt


0

โพสต์เหตุการณ์สร้างสำหรับ Visual Studio

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

-1

พิจารณาใช้

git-rev-label

ให้ข้อมูลเกี่ยวกับการแก้ไข Git master-c73-gabc6becพื้นที่เก็บข้อมูลในรูปแบบเช่น สามารถเติมสตริงแม่แบบหรือไฟล์ที่มีตัวแปรสภาพแวดล้อมและข้อมูลจาก Git มีประโยชน์ในการให้ข้อมูลเกี่ยวกับเวอร์ชันของโปรแกรม: branch, tag, commit hash, commits count, สถานะสกปรก, วันที่และเวลา หนึ่งในสิ่งที่มีประโยชน์มากที่สุดคือการนับการกระทำไม่ใช่คำนึงถึงการรวมสาขา - เพียงผู้ปกครองคนแรก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.