git rebase โดยไม่เปลี่ยนการกระทำที่ประทับเวลา


157

มันจะทำให้รู้สึกถึงการปฏิบัติgit rebaseในขณะที่รักษา timestamps กระทำ?

ฉันเชื่อว่าผลที่ตามมาก็คือสาขาใหม่จะไม่จำเป็นต้องมีวันที่ตามลำดับเวลา เป็นไปได้ในทางทฤษฎีหรือไม่? (เช่นใช้คำสั่งการวางท่อเพียงแค่อยากรู้อยากเห็นที่นี่)

หากเป็นไปได้ในทางทฤษฎีแล้วมันเป็นไปได้ในทางปฏิบัติกับ rebase ไม่เปลี่ยน timestamps?

ตัวอย่างเช่นสมมติว่าฉันมีต้นไม้ต่อไปนี้:

master <jun 2010>
  |
  :
  :
  :     oldbranch <feb 1984>
  :     /
oldcommit <jan 1984>

ตอนนี้ถ้าฉัน rebase oldbranchบนmasterวันที่ของการกระทำการเปลี่ยนแปลงจาก feb 1984 ถึงมิถุนายน 2010 มันเป็นไปได้ที่จะเปลี่ยนพฤติกรรมนั้นเพื่อให้การประทับเวลากระทำจะไม่เปลี่ยนแปลง? ในที่สุดฉันก็จะได้รับ:

      oldbranch <feb 1984>
      /
 master <jun 2010>
    |
    :

มันจะสมเหตุสมผลไหม? มันอนุญาตให้ในคอมไพล์มีประวัติซึ่งการคอมมิชชันเก่ามีการคอมมิทล่าสุดหรือไม่?


3
มันตลกมากที่คำตอบของคำถามคือ "คุณไม่จำเป็นต้องทำอะไรเลย - นั่นคือวิธีการทำงานที่เป็นค่าเริ่มต้น" แต่ตอนนี้สมมติว่าคุณต้องการคอมมิทให้เรียงลำดับวันที่อย่างถูกต้องขณะทำการรีบูต (ซึ่งเป็นสถานการณ์ที่ค่อนข้างเป็นธรรมชาติถ้าคุณคิดเกี่ยวกับมัน) ตอนนี้ผมไม่สามารถที่จะหาวิธีการที่จะประสบความสำเร็จที่และโพสต์คิวของฉันเป็นstackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon

1
เดวิดพูดถึงตัวเลือกอื่นในการรีเซ็ตวันที่ส่งมอบ: git rebase --committer-date-is-author-date SHA. ดูคำตอบที่แก้ไขของฉันด้านล่าง
VonC

ฉันเพิ่งเขียนคำตอบที่ครอบคลุมในคำถามที่คล้ายกันซึ่งผู้เขียนลองคำตอบที่อธิบายไว้ที่นี่และไม่สามารถใช้พวกเขาในลักษณะที่น่าพอใจ
axiac

คำตอบ:


149

อัปเดตมิถุนายน 2557: David Fraserกล่าวถึงความคิดเห็นวิธีการแก้ปัญหายังมีรายละเอียดใน " เปลี่ยนการประทับเวลาขณะรีสาขา git " โดยใช้ตัวเลือก--committer-date-is-author-date(เปิดตัวครั้งแรกในเดือนมกราคม 2009 ในการกระทำ 3f01ad6

โปรดทราบว่า--committer-date-is-author-dateตัวเลือกดูเหมือนว่าจะปล่อยให้บันทึกเวลาของผู้เขียนและตั้งค่าการประทับเวลาของตัวส่งสัญญาณให้เป็นเช่นเดียวกับเวลาบันทึกของผู้แต่งดั้งเดิมซึ่งเป็นสิ่งที่ OP Olivier Verdierต้องการ

ฉันพบการกระทำครั้งสุดท้ายด้วยวันที่ที่ถูกต้องและทำ:

git rebase --committer-date-is-author-date SHA

ดูgit am:

--committer-date-is-author-date

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


(คำตอบเดิมมิถุนายน 2012)

คุณอาจจะลองสำหรับที่ไม่ใช่แบบโต้ตอบ rebase

git rebase --ignore-date

(จากคำตอบ SOนี้ )

สิ่งนี้ผ่านไปgit amแล้วซึ่งกล่าวถึง:

 --ignore-date

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

สำหรับ git rebaseตัวเลือกนี้คือ "เข้ากันไม่ได้กับตัวเลือก - แบบโต้ตอบ"

เนื่องจากคุณสามารถเปลี่ยนแปลงเวลาของวันที่ส่งมอบเก่า (ด้วยgit filter-branch) ได้ฉันคิดว่าคุณสามารถจัดระเบียบประวัติ Git ของคุณด้วยคำสั่งที่คุณต้องการ / ต้องการแม้กระทั่งกำหนดไว้สำหรับอนาคต! .


ดังที่โอลิเวียร์กล่าวถึงในคำถามของเขาวันที่ผู้แต่งจะไม่เปลี่ยนแปลงโดยการคืนเงิน
จากหนังสือ Pro Git :

  • ผู้เขียนคือคนที่สร้างสรรค์งาน
  • ในขณะที่ผู้เดินทางคือคนสุดท้ายที่ใช้งาน

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

เพื่อให้ชัดเจนยิ่งขึ้นในกรณีนี้ตามความคิดเห็นของ Olivier:

--ignore-dateไม่ตรงข้ามของสิ่งที่ผมพยายามที่จะบรรลุ !
กล่าวคือลบการประทับเวลาของผู้แต่งและแทนที่ด้วยการยืนยันเวลา!
ดังนั้นคำตอบที่ถูกต้องสำหรับคำถามของฉันคือ:
อย่าทำอะไรเลยเนื่องจากgit rebase จริง ๆ แล้วไม่เปลี่ยนการประทับเวลาของผู้เขียนโดยค่าเริ่มต้น



1
ที่น่าสนใจเกี่ยวกับวันที่โดยพลการที่จะกระทำ อย่างไรก็ตามgit rebase --ignore-dateไม่ทำงาน มันเปลี่ยนวันที่ของการกระทำที่ถูกปฏิเสธ
Olivier Verdier

@ Olivier: แปลก: คุณได้ทำการปฏิเสธแบบไม่โต้ตอบหรือไม่? และระหว่างวันที่ผู้แต่งและวันผู้ส่งเราแน่ใจว่าได้ตรวจสอบวันที่ "ถูกต้อง" หรือไม่?
VonC

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

4
จะแม่นยำมากขึ้นคือ--ignore-dateไม่ตรงข้ามของสิ่งที่ผมพยายามที่จะบรรลุ! กล่าวคือลบการประทับเวลาของผู้แต่งและแทนที่ด้วยการยืนยันเวลา! ดังนั้นคำตอบที่ถูกต้องสำหรับคำถามของฉันคือ: อย่าทำอะไรเลยเนื่องจากgit rebaseไม่ได้เปลี่ยนการประทับเวลาของผู้เขียนตามค่าเริ่มต้น
Olivier Verdier

5
โปรดทราบว่า--committer-date-is-author-dateตัวเลือกนั้นดูเหมือนว่าจะปล่อยให้ผู้เขียนบันทึกเวลาและตั้งค่าการประทับเวลาของ committer ให้เป็นเช่นเดียวกับการบันทึกเวลาของผู้แต่งดั้งเดิมซึ่งเป็นสิ่งที่ Olivier ต้องการ ...
David Fraser

118

หากคุณเมาแล้วยอมรับวันที่กระทำ (อาจมีการรีบูต) และต้องการรีเซ็ตพวกเขาเป็นวันที่ผู้เขียนที่เกี่ยวข้องคุณสามารถเรียกใช้:

git filter-branch --env-filter 'GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; export GIT_COMMITTER_DATE'


1
ฉันเพิ่งลองสิ่งนี้ แต่ไม่มีผลใด ๆ ผมได้รับการส่งออก WARNING: Ref 'refs/heads/master' is unchangedfolowing: ฉันใช้ git เวอร์ชั่น 1.7.9.5 บน Linux (64 บิต)
Markus N.

20
ฉันต้องการเพิ่มวิธีการอื่นถ้าคุณเมาแล้ว แต่ไม่ต้องการวนซ้ำประวัติศาสตร์ทั้งหมด: git rebase --committer-date-is-author-date <base_branch> ด้วยวิธีนี้ git จะรีเซ็ตวันที่ส่งมอบเฉพาะสำหรับคอมมิทที่ใช้กับ <base_branch> (ซึ่งอาจเป็น ชื่อสาขาเดียวกับที่คุณใช้เมื่อคุณเมาขึ้น)
speakman

คำตอบที่ยอมรับไม่สามารถใช้งานได้ในปี 2016 แต่คำตอบของ @ speakman ก็ใช้ได้!
Theodore R. Smith

2
@ คำตอบของ speakman ไม่ทำงานในเดือนตุลาคม 2559 แต่ Andy's ทำ!
Amedee Van Gasse

2
สิ่งนี้ไม่ทำงานบน Windows ฉันสามารถใช้งาน Windows Bash ได้
vaindil

33

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

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


3
+1 - ฉันมีนามแฝงคอมไพล์ในสถานที่ ( coderwall.com/p/euwpig/a-better-git-log ) ที่เห็นได้ชัดว่าใช้เวลาประทับของผู้เดินทางซึ่งทำให้ฉันสับสน บันทึก Gitk และ git แสดงการประทับเวลาของผู้แต่ง
1615903

15

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

ก่อนอื่นตรวจสอบให้แน่ใจว่าแต่ละการกระทำที่คุณกำลังจะทำการ rebase นั้นมีข้อความการส่งที่ไม่ซ้ำใครและการประทับเวลาของผู้เขียน (นี่คือเคล็ดลับที่ต้องปรับปรุงในขณะนี้มันเหมาะกับความต้องการของฉัน)

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

#NOTE: BASE is the commit where your rebase begins
git log --pretty='%ct %at %s' BASE..HEAD > hashlog

จากนั้นให้รีบูทจริงเกิดขึ้น

สุดท้ายเราเปลี่ยนการประทับเวลา committer git filter-branchปัจจุบันกับหนึ่งที่บันทึกไว้ในแฟ้มถ้ากระทำข้อความเป็นเดียวกันโดยใช้

 git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%at %s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_COMMITTER_DATE=$__date || cat'

หากมีข้อผิดพลาดเพียงแค่ชำระเงินgit reflogหรือrefs/original/อ้างอิงทั้งหมด

คุณสามารถทำสิ่งเดียวกันกับเวลาของผู้เขียนได้

ตัวอย่างเช่นหากการประทับเวลาของผู้แต่งบางคำสั่งไม่เป็นระเบียบและไม่มีการจัดเรียงข้อตกลงใหม่เราเพียงต้องการให้การประทับเวลาของผู้เขียนแสดงตามลำดับคำสั่งต่อไปนี้จะช่วยได้

git log --pretty='%at %s' COMMIT1..COMMIT2 > hashlog
join -1 1 -2 1 <(cat hashlog | cut -f 1 | sort -nr | awk '{ print NR" "$1 }') <(cat hashlog | awk '{ print NR" "$0 }') | cut -d" " -f2,4- > hashlog_
mv hashlog_ hashlog
git filter-branch --env-filter '__date=$(__log=$(git log -1 --pretty="%s" $GIT_COMMIT); grep -m 1 "$__log" ../../hashlog | cut -d" " -f1); test -n "$__date" && export GIT_AUTHOR_DATE=$__date || cat'

นี่เป็นเคล็ดลับที่ยอดเยี่ยม! มันอนุญาตให้ฉันเขียน 75 คอมมิทแทนที่จะเป็น 1100+ จากการใช้คำตอบอื่น ๆ
audun

มันยอดเยี่ยมมาก! มีวิธีแก้ไขสคริปต์เพื่อรักษาคอมมิชชันดั้งเดิมด้วยหรือไม่
David DeMar

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