git rebase mà không thay đổi dấu thời gian cam kết


157

Nó sẽ có ý nghĩa để thực hiện git rebasetrong khi bảo quản dấu thời gian cam kết?

Tôi tin rằng một hậu quả sẽ là chi nhánh mới sẽ không nhất thiết phải có ngày cam kết theo thời gian. Đó là lý thuyết có thể ở tất cả? (ví dụ: sử dụng các lệnh hệ thống ống nước; chỉ tò mò ở đây)

Nếu về mặt lý thuyết là có thể, thì có thể trong thực tế với rebase, không thay đổi dấu thời gian?

Ví dụ: giả sử tôi có cây sau:

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

Bây giờ, nếu tôi rebase oldbranchtrên master, ngày cam kết thay đổi từ tháng 2 năm 1984 đến tháng sáu năm 2010. Có thể thay đổi hành vi đó để cam kết timestamp là không thay đổi? Cuối cùng, tôi sẽ có được:

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

Điều đó sẽ có ý nghĩa gì cả? Nó thậm chí còn được phép trong git để có một lịch sử trong đó một cam kết cũ có một cam kết gần đây hơn với tư cách là cha mẹ?


3
Thật thú vị khi câu trả lời cho câu hỏi thực sự là "bạn không cần phải làm gì cả - đó là cách nó hoạt động mặc định". Nhưng bây giờ, giả sử bạn muốn cam kết được sắp xếp theo thứ tự ngày thích hợp trong khi thực hiện rebase (đó là kịch bản khá tự nhiên nếu bạn nghĩ về nó). Bây giờ, tôi không thể tìm cách đạt được điều đó và đã đăng q của mình dưới dạng stackoverflow.com/questions/12270357/really-flatten-a-git-merge
pfalcon

1
David đề cập đến một tùy chọn khác để thiết lập lại ngày giao dịch : git rebase --committer-date-is-author-date SHA. Xem câu trả lời được chỉnh sửa của tôi dưới đây
VonC

Tôi vừa viết một câu trả lời mở rộng cho một câu hỏi tương tự mà tác giả đã thử các câu trả lời được giải thích ở đây và không thể áp dụng chúng một cách thỏa đáng.
axiac

Câu trả lời:


149

Cập nhật tháng 6 năm 2014: David Fraser đề cập trong các ý kiến một giải pháp cũng được nêu chi tiết trong " Thay đổi dấu thời gian trong khi khởi động lại nhánh git ", sử dụng tùy chọn --committer-date-is-author-date(được giới thiệu ban đầu vào tháng 1 năm 2009 trong cam kết 3f01ad6

Lưu ý rằng --committer-date-is-author-datetùy chọn dường như rời khỏi dấu thời gian của tác giả và đặt dấu thời gian của dấu phẩy giống với dấu thời gian của tác giả ban đầu, đó là điều mà OP Olivier Verdier muốn.

Tôi đã tìm thấy cam kết cuối cùng với ngày chính xác và đã làm:

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

Xem git am:

--committer-date-is-author-date

Theo mặc định, lệnh ghi lại ngày từ thông điệp email là ngày tác giả cam kết và sử dụng thời gian tạo cam kết làm ngày bắt đầu.
Điều này cho phép người dùng nói dối về ngày giao dịch bằng cách sử dụng cùng giá trị với ngày tác giả .


(Câu trả lời gốc, tháng 6 năm 2012)

Bạn có thể thử, cho một rebase không tương tác

git rebase --ignore-date

(từ câu trả lời SO này )

Điều này được thông qua git am, trong đó đề cập đến:

 --ignore-date

Theo mặc định, lệnh ghi lại ngày từ thông điệp email là ngày tác giả cam kết và sử dụng thời gian tạo cam kết làm ngày bắt đầu.
Điều này cho phép người dùng nói dối về ngày của tác giả bằng cách sử dụng cùng một giá trị với ngày bắt đầu.

Dành cho git rebase , tùy chọn này là "Không tương thích với tùy chọn - tương tác."

bạn có thể thay đổi dấu thời gian của ngày cam kết cũ (với git filter-branch), tôi cho rằng bạn có thể sắp xếp lịch sử Git của mình với bất kỳ thứ tự ngày cam kết nào bạn muốn / cần, thậm chí đặt nó trong tương lai! .


Như Olivier đã đề cập trong câu hỏi của mình, ngày tác giả không bao giờ bị thay đổi bởi một cuộc nổi loạn;
Từ sách Git Pro :

  • Tác giả là người ban đầu viết tác phẩm,
  • trong khi người đi làm là người cuối cùng áp dụng công việc.

Vì vậy, nếu bạn gửi một bản vá cho một dự án và một trong những thành viên cốt lõi áp dụng bản vá, cả hai bạn đều nhận được tín dụng.

Để rõ ràng hơn, trong trường hợp này, như nhận xét của Olivier:

các --ignore-datelàm ngược lại những gì tôi đã cố gắng để đạt được !
Cụ thể, nó xóa dấu thời gian của tác giả và thay thế chúng bằng dấu thời gian cam kết!
Vì vậy, câu trả lời đúng cho câu hỏi của tôi là:
Không làm gì cả, vì git rebase thực tế không thay đổi dấu thời gian của tác giả theo mặc định.



1
Thú vị về ngày tùy ý để cam kết. Tuy nhiên, git rebase --ignore-datekhông hoạt động. Nó thay đổi ngày của các cam kết bị từ chối.
Olivier Verdier

@Olivier: lạ: bạn đã thực hiện một cuộc nổi loạn không tương tác? Và giữa Ngày tác giả và Ngày ủy quyền, chúng tôi có chắc chắn theo dõi ngày "đúng" không?
VonC

1
Cảm ơn VonC, sự khác biệt giữa dấu thời gian của tác giả và người đi làm, đó là điều làm cho tất cả đột nhiên rõ ràng. Tôi đã viết câu trả lời cho câu hỏi của mình trong bài viết của mình, nhưng hãy thoải mái điều chỉnh câu trả lời của bạn để phản ánh điều đó.
Olivier Verdier

4
nói chính xác hơn: --ignore-dateđiều ngược lại với những gì tôi đã cố gắng đạt được! Cụ thể, nó xóa dấu thời gian của tác giả và thay thế chúng bằng dấu thời gian cam kết! Vì vậy, câu trả lời đúng cho câu hỏi của tôi là: không làm gì cả, vì git rebasethực tế không thay đổi dấu thời gian của tác giả theo mặc định.
Olivier Verdier

5
Lưu ý rằng --committer-date-is-author-datetùy chọn dường như rời khỏi dấu thời gian của tác giả và đặt dấu thời gian của người đi làm giống với dấu thời gian của tác giả ban đầu, đó là điều mà Olivier muốn ...
David Fraser

118

Nếu bạn đã làm hỏng ngày cam kết (có lẽ với một rebase) và muốn đặt lại chúng thành ngày tác giả tương ứng của họ, bạn có thể chạy:

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


1
Tôi chỉ thử điều này, nhưng không có hiệu quả. Tôi đã nhận được đầu ra folowing : WARNING: Ref 'refs/heads/master' is unchanged. Tôi đang sử dụng git phiên bản 1.7.9.5 trên Linux (64 bit)
Markus N.

20
Tôi muốn thêm một cách tiếp cận khác nếu bạn đã làm hỏng nhưng không muốn lặp lại toàn bộ lịch sử: git rebase --committer-date-is-author-date <base_branch> Bằng cách này, git sẽ chỉ đặt lại ngày cam kết cho các cam kết được áp dụng trên <base_branch> (có lẽ là cùng tên chi nhánh bạn đã sử dụng khi bạn bắt vít).
nói chuyện

Câu trả lời được chấp nhận đã không hoạt động vào năm 2016, nhưng câu trả lời của @ speakman đã làm!
Theodore R. Smith

2
Câu trả lời của @ speakman không hoạt động vào tháng 10 năm 2016, nhưng Andy đã làm!
Amedee Van Gasse

2
Điều này không hoạt động trên Windows. Tôi đã có thể làm cho nó hoạt động bằng Windows Bash.
vaindil

33

Một câu hỏi quan trọng của Von C giúp tôi hiểu những gì đang xảy ra: khi rebase của bạn, của committer thay đổi dấu thời gian, nhưng không phải là của tác giả dấu thời gian, mà đột nhiên tất cả có ý nghĩa. Vì vậy, câu hỏi của tôi thực sự không đủ chính xác.

Câu trả lời là rebase thực sự không thay đổi dấu thời gian của tác giả (bạn không cần phải làm gì cho việc đó), điều này hoàn toàn phù hợp với tôi.


3
+1 - Tôi có một bí danh git tại chỗ ( coderwall.com/p/euwpig/a-better-git-log ) rõ ràng sử dụng dấu thời gian của người giao dịch, điều này làm tôi bối rối. Cả Gitk và git log đều hiển thị dấu thời gian của tác giả.
1615903

15

Theo mặc định, git rebase sẽ đặt dấu thời gian của committer thành thời gian khi cam kết mới được tạo, nhưng vẫn giữ nguyên dấu thời gian của tác giả. Hầu hết thời gian, đây là hành vi mong muốn, nhưng tại một số trường hợp, chúng tôi chấm không muốn thay đổi dấu thời gian của người đi làm. Làm thế nào chúng ta có thể thực hiện điều đó? Vâng, đây là mẹo tôi thường làm.

Trước tiên, hãy đảm bảo rằng mỗi cam kết bạn sắp sửa có một thông báo cam kết duy nhất và dấu thời gian của tác giả (Đây là nơi cần lừa cải tiến, hiện tại nó phù hợp với nhu cầu của tôi).

Trước khi rebase, ghi lại dấu thời gian của người ủy quyền, dấu thời gian của tác giả và thông báo cam kết của tất cả các cam kết sẽ được chuyển sang một tệp.

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

Sau đó, hãy để cuộc nổi loạn thực sự diễn ra.

Cuối cùng, chúng tôi thay thế dấu thời gian của người chuyển đổi hiện tại bằng dấu thời gian được ghi trong tệp nếu thông báo cam kết giống nhau bằng cách sử dụng 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'

Nếu có gì sai, chỉ cần kiểm tra git refloghoặc tất cả các refs/original/ref.

Furthormore, bạn có thể làm điều tương tự với dấu thời gian của tác giả.

Ví dụ: nếu dấu thời gian của tác giả không đúng thứ tự và không sắp xếp lại các cam kết này, chúng tôi chỉ muốn dấu thời gian của tác giả hiển thị theo thứ tự, thì các lệnh sau sẽ có ích.

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'

Đây là một mẹo hay! Nó cho phép tôi chỉ viết lại 75 cam kết thay vì 1100+ từ việc sử dụng các câu trả lời khác.
audun

Cái này thật tuyệt! Có cách nào để sửa đổi tập lệnh để giữ nguyên committer gốc không?
David DeMar

@DavidDeMar cũng vậy, chỉ cần thay đổi nhật ký git --pretty để ghi lại email gốc và sửa đổi tập lệnh cho phù hợp.
weynhamz
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.