Bagaimana cara mengubah cap waktu komit lama di Git?


747

Jawaban untuk Bagaimana mengubah komitmen yang ada dan tidak dicuri? menjelaskan cara untuk mengubah pesan komit sebelumnya yang belum didorong ke atas. Pesan baru mewarisi stempel waktu dari komitmen asli. Ini tampaknya logis, tetapi apakah ada cara untuk mengatur ulang waktunya?



34
git commit --amend --reset-author
Erick M. Sprengel

Jawaban:


535

Gunakan git filter-branchdengan filter env yang menetapkan GIT_AUTHOR_DATEdan GIT_COMMITTER_DATEuntuk hash spesifik dari komit yang ingin Anda perbaiki.

Ini akan membatalkan itu dan semua hash di masa depan.

Contoh:

Jika Anda ingin mengubah tanggal komit 119f9ecf58069b265ab22f1f97d2b648faf932e0, Anda dapat melakukannya dengan sesuatu seperti ini:

git filter-branch --env-filter \
    'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]
     then
         export GIT_AUTHOR_DATE="Fri Jan 2 21:38:53 2009 -0800"
         export GIT_COMMITTER_DATE="Sat May 19 01:01:01 2007 -0700"
     fi'


8
Itu menemukan nilai yang benar, tetapi hanya pengaturan variabel-variabel itu tampaknya tidak benar-benar mempengaruhi tanggal dari komit lama.
IQAndreas

36
Apa yang Anda maksud dengan "Ini akan membatalkan itu dan semua hash di masa depan."?
EpicDavi

16
EpicDavi: Ini berarti bahwa Anda harus memaksa mendorong ke repositori jarak jauh, dan siapa pun yang telah menarik komit atau komit di masa depan harus mengatur ulang dan menarik, atau menghapus dan mengkloning dari awal. Sejauh yang saya tahu, tidak ada metode yang mengatasi ini.
EriF89

4
Sama seperti catatan untuk pemula, hash pendek tidak berfungsi dalam pernyataan if, gunakan SHA-1
40detectives yang panjang

780

Anda dapat melakukan rebase interaktif dan memilih edit untuk komit yang ingin Anda ubah tanggalnya. Ketika proses rebase berhenti untuk mengubah komit yang Anda ketikkan misalnya:

git commit --amend --date="Wed Feb 16 14:00 2011 +0100"

Setelah itu Anda melanjutkan rebase interaktif Anda.

UPDATE (sebagai tanggapan atas komentar studgeek): untuk mengubah tanggal komit dan bukan tanggal penulis:

GIT_COMMITTER_DATE="Wed Feb 16 14:00 2011 +0100" git commit --amend

Baris di atas menetapkan variabel lingkungan GIT_COMMITTER_DATE yang digunakan dalam amend komit.

Semuanya diuji di Git Bash.


22
@nschum --date = "" dan --data "non-date-text" semuanya menghasilkan hasil yang sama, dengan mengambil tanggal sekarang.
Paul Pladijs

12
on git versi 1.7.7.1 menggunakan --date = "now" memberikan fatal: format tanggal tidak valid: sekarang
Aragorn

4
Ketika komit yang tanggalnya ingin Anda ubah adalah komit terbaru, Anda tidak harus melakukannya rebase, Anda bisa melakukannyagit commit --amend
Eponim

7
Alih-alih mengekspor GIT_COMMITTER_DATE = "", coba batalkan GIT_COMMITTER_DATE.
Mark E. Haase

2
Saya menggunakan --no-edit sehingga Anda dapat menggunakan skrip otomatis! + var fixedDate = strftime(new Date(), "%c"); + var result = shelljs.exec("git commit --amend --date=\"" + fixedDate + "\" --no-edit");
Marcello de Sales

392

Cara yang lebih baik untuk menangani semua saran ini dalam satu perintah adalah

LC_ALL=C GIT_COMMITTER_DATE="$(date)" git commit --amend --no-edit --date "$(date)"

Ini akan menetapkan komit terakhir dan tanggal penulis menjadi "sekarang."


22
Ini berfungsi baik untuk mengedit komit tertentu selama rebase interaktif.
friederbluemle

2
Anda juga bisa menambahkan alias ke shell
kaleissin

14
Tampaknya Git tidak mengetahui format tanggal, jadi untuk sepenuhnya benar, Anda harus membuatnya menjadi seperti ini:LANG= GIT_COMMITTER_DATE="`date`" git commit --amend --date "`date`"
Michał Góral

Saya melakukan itu ketika saya rebase dan squash cabang, sehingga membuat satu komit dengan cap waktu yang diperbarui.
Luke Ehresman

12
Anda juga bisa melakukannya --date "now". Git> = 2 akan menafsirkannya.
wisbucky

189

Lakukan saja git commit --amend --reset-author --no-edit. Untuk komit yang lebih lama, Anda dapat melakukan rebase interaktif dan memilih edituntuk komit yang tanggalnya ingin Anda ubah.

git rebase -i <ref>

Kemudian ubah komit dengan --reset-authordan --no-edituntuk mengubah tanggal penulis ke tanggal saat ini:

git commit --amend --reset-author --no-edit

Terakhir, lanjutkan dengan rebase interaktif Anda:

git rebase --continue

5
panggilan yang baik untuk menggunakan --reset-author, ini baru dalam git 1.6.6 (ref gitlog.wordpress.com/2010/01/13/git-1-6-6 )
Tim Abell

1
Ini berfungsi dengan baik untuk membuat Github menunjukkan komitmen dari PR yang dirangkum dalam urutan yang benar, karena mereka memesannya dengan stempel waktu dan tanpa trik ini, stempel waktu semua mungkin sama.
Nathan Long

4
note --reset-authorakan mengatur ulang Penulis dan Tanggal Penulis ke sekarang.
wisbucky

apakah ini akan mengubah "TANGGAL KOMITTER" pada saat yang sama?
luochen1990

134

Saya menulis naskah dan paket Homebrew untuk ini. Sangat mudah dipasang, Anda dapat menemukannya di PotatoLabs/git-redatehalaman GitHub .

Sintaksis:

git redate -c 3

Anda hanya perlu menjalankan git redatedan Anda akan dapat mengedit semua tanggal dalam vim dari 5 commit terbaru (ada juga -copsi untuk berapa banyak commit yang ingin Anda kembalikan, itu hanya default ke 5). Beri tahu saya jika Anda memiliki pertanyaan, komentar, atau saran!

masukkan deskripsi gambar di sini


2
Hal-hal hebat, meskipun saya harus menggunakan vim daripada nano
howdoyouturnthison

Terima kasih @Edmund untuk skrip yang bagus. Saya tidak dapat melihat tanggal untuk diedit di vi setelah saya menjalankan git redate -c. Yang saya lihat adalah% cI | XXXXXXXXXXXXXXXX | Komit awal. Bisakah Anda membantu? Terima kasih
Kiem Nguyen

@ KiemNguyen bisakah kamu mencoba git redate (tanpa -c)?
bigpotato

4
sepenuhnya setuju dengan Mina dan @howdoyouturnthison di sini, mengapa Anda tidak membuatnya editor agnostic via variabel lingkungan EDITOR? (juga saya di linux, bukan mac ...)
ympostor

3
Terima kasih @Edmund! Untuk berjaga-jaga, skrip Anda memiliki masalah dengan penanganan nilai default untuk COMMITS. Jika tidak disetel, kode berikut menerapkan filter hanya untuk (saya kira / menemukan) komit terakhir. "git filter-branch -f --env-filter" $ ENVFILTER "HEAD ~ $ COMMITS..HEAD> / dev / null"
Grigory Entin

103

Setiap komit dikaitkan dengan dua tanggal, tanggal komiter dan tanggal penulis. Anda dapat melihat tanggal-tanggal ini dengan:

git log --format=fuller

Jika Anda ingin mengubah tanggal penulis dan tanggal komiter dari 6 komitmen terakhir, Anda dapat menggunakan rebase interaktif:

git rebase -i HEAD~6

.

pick c95a4b7 Modification 1
pick 1bc0b44 Modification 2
pick de19ad3 Modification 3
pick c110e7e Modification 4
pick 342256c Modification 5
pick 5108205 Modification 6

# Rebase eadedca..5108205 onto eadedca (6 commands)
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
# d, drop = remove commit

Untuk semua komitmen di mana Anda ingin mengubah tanggal, ganti pickdengan edit(atau hanya e), lalu simpan dan keluar dari editor Anda.

Anda sekarang dapat mengubah setiap komit dengan menentukan tanggal penulis dan tanggal committer dalam format ISO-8601:

GIT_COMMITTER_DATE="2017-10-08T09:51:07" git commit --amend --date="2017-10-08T09:51:07"

Tanggal pertama adalah tanggal komit, yang kedua adalah tanggal penulis.

Lalu pergi ke komit berikutnya dengan:

git rebase --continue

Ulangi proses ini sampai Anda mengubah semua komitmen Anda. Periksa perkembangan Anda dengan git status.


1
Saya mengikuti ini dan berakhir pada 'kepala yang terlepas'!
Simon H

1
@Simon H Saya sudah menguji lagi jawaban saya dan itu bekerja dengan baik. Anda harus mengetik sesuatu yang berbeda atau Anda sudah berada di kepala yang terpisah. Jika Anda ingin kembali dari kepala yang terpisah, lakukan a git checkout name-of-current-branch.
Ortomala Lokni

4
Ini adalah jawaban terbaik dan termudah. Tip kecil: digunakan --no-edit di git commit --amend --no-edit --date=2017-10-08T09:51:07untuk menjaga tua pesan commit.
Mariusz Pawelski

2
Anda mungkin juga ingin memperbarui GIT_COMMITTER_DATE sebagaimana dijelaskan di sini eddmann.com/posts/…
smihael

2
@smihael Terima kasih atas tautannya. Saya telah memasukkan saran Anda dalam jawaban saya.
Ortomala Lokni


44

Membangun theosp 's jawaban , saya menulis sebuah script yang disebut git-cdc(untuk tanggal perubahan komit) yang saya dimasukkan ke dalam saya PATH.

Nama itu penting: git-xxxdi mana saja di Anda PATHmemungkinkan Anda mengetik:

git xxx
# here
git cdc ... 

Skrip itu ada di bash, bahkan di Windows (karena Git akan memanggilnya dari lingkungan msys -nya )

#!/bin/bash
# commit
# date YYYY-mm-dd HH:MM:SS

commit="$1" datecal="$2"
temp_branch="temp-rebasing-branch"
current_branch="$(git rev-parse --abbrev-ref HEAD)"

date_timestamp=$(date -d "$datecal" +%s)
date_r=$(date -R -d "$datecal")

if [[ -z "$commit" ]]; then
    exit 0
fi

git checkout -b "$temp_branch" "$commit"
GIT_COMMITTER_DATE="$date_timestamp" GIT_AUTHOR_DATE="$date_timestamp" git commit --amend --no-edit --date "$date_r"
git checkout "$current_branch"
git rebase  --autostash --committer-date-is-author-date "$commit" --onto "$temp_branch"
git branch -d "$temp_branch"

Dengan itu, Anda dapat mengetik:

git cdc @~ "2014-07-04 20:32:45"

Itu akan mengatur ulang tanggal komitmen / komit sebelum HEAD ( @~) ke tanggal yang ditentukan.

git cdc @~ "2 days ago"

Itu akan mengatur ulang tanggal pembuat / komit sebelum komit ( @~) ke jam yang sama, tetapi 2 hari yang lalu.


Ilya Semenov menyebutkan dalam komentar :

Untuk OS X Anda juga dapat menginstal GNU coreutils( brew install coreutils), menambahkannya ke PATH( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") dan kemudian menggunakan 2 days agosintaksis " ".


1
Bagi saya ini hanya bekerja dengan mengutip tanggal dan waktu menjadi satu kutipan: git cdc @~ "2014-07-04 20:32:45jika tidak maka tidak akan mengenali waktu dan karenanya memperoleh waktu 00:00:00 (itu menjadi argumen ketiga).
peschü

3
Untuk OS X Anda juga dapat menginstal GNU coreutils ( brew install coreutils), menambahkannya ke PATH ( PATH="/usr/local/opt/coreutils/libexec/gnubin:$PATH") dan kemudian menggunakan sintaks "2 hari yang lalu".
Ilya Semenov

1
@IlyaSemenov Menarik. Saya telah memasukkan komentar Anda dalam jawaban untuk lebih banyak visibilitas.
VonC

Saya mencoba menggunakan contoh pertama Anda tetapi saya tetap mendapatkan "fatal: format tanggal tidak valid:". Format tanggal apa yang diharapkan Mac OS X?
usbsnowcrash

@ usbsnowcrash tidak yakin pada mac. Apakah contoh kedua " 2 days ago" bekerja?
VonC

25

Cara Mengedit Beberapa Tanggal Komit

Jawaban lain sangat tidak nyaman untuk mengedit beberapa tanggal komit. Saya kembali ke pertanyaan ini setelah beberapa tahun untuk berbagi teknik.

Untuk mengubah tanggal dari 4 komitmen terakhir:

git rebase -i HEAD~4

Edit rebase sebagai berikut, masukkan execbaris untuk mengubah tanggal sesuai kebutuhan:

pick 4ca564e Do something
exec git commit --amend --no-edit --date "1 Oct 2019 12:00:00 PDT"
pick 1670583 Add another thing
exec git commit --amend --no-edit --date "2 Oct 2019 12:00:00 PDT"
pick b54021c Add some tests
exec git commit --amend --no-edit --date "3 Oct 2019 12:00:00 PDT"
pick e8f6653 Fix the broken thing
exec git commit --amend --no-edit --date "4 Oct 2019 12:00:00 PDT"

Penggunaan --amend/ --dateopsi yang bagus. Lebih sederhana daripada jawaban saya sendiri menggunakan variabel lingkungan. Terpilih.
VonC

Apakah mungkin menggunakan tanggal / waktu saat ini sebagai parameter?
accfews

Itu GIT_AUTHOR_DATEhanya pembaruan .
Blaise

Kembali. 'Apakah mungkin menggunakan tanggal / waktu saat ini sebagai parameter?': "Sekarang" dipahami sebagai tanggal yang valid, sehingga garis eksekutif di atas akan menjadiexec git commit --amend --no-edit --date "now"
Andrew Richards

20

jika itu adalah komit terakhir sebelumnya.

git rebase  -i HEAD~2
git commit --amend --date=now

jika Anda sudah mendorong ke orgin dan dapat memaksa menggunakan:

git push --force 

jika Anda tidak dapat memaksa dan jika didorong, Anda tidak dapat mengubah komit! .


18

Berikut ini adalah alias yang nyaman yang mengubah waktu komit dan penulis dari komit terakhir ke waktu yang diterima oleh date --date:

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && GIT_COMMITTER_DATE=\"$d\" \
            git commit --amend --date \"$d\""

Pemakaian: git cd <date_arg>

Contoh:

git cd now  # update the last commit time to current time
git cd '1 hour ago'  # set time to 1 hour ago

Sunting: Ini adalah versi yang lebih otomatis yang memeriksa apakah indeksnya bersih (tidak ada perubahan yang tidak dikomit) dan menggunakan kembali pesan komit terakhir, atau gagal jika tidak (pembodohan):

[alias]
    cd = "!d=\"$(date -d \"$1\")\" && shift && \
        git diff-index --cached --quiet HEAD --ignore-submodules -- && \
        GIT_COMMITTER_DATE=\"$d\" git commit --amend -C HEAD --date \"$d\"" \
        || echo >&2 "error: date change failed: index not clean!"

17

Saya membuat paket npm ini untuk mengubah tanggal dari komitmen lama.

https://github.com/bitriddler/git-change-date

Penggunaan sampel:

npm install -g git-change-date
cd [your-directory]
git-change-date

Anda akan diminta untuk memilih komit yang ingin Anda modifikasi kemudian untuk memasukkan tanggal baru.

Jika Anda ingin mengubah komit dengan hash tertentu jalankan ini git-change-date --hash=[hash]


Saya hanya ingin mengatakan bahwa ini hebat dan bekerja dengan indah. Terima kasih, Anda telah menyelamatkan saya banyak waktu!
paranza

17

Fungsi bash berikut akan mengubah waktu komit di cabang saat ini.

Berhati-hatilah untuk tidak menggunakan jika Anda sudah mendorong komit atau jika Anda menggunakan komit di cabang lain.

# rewrite_commit_date(commit, date_timestamp)
#
# !! Commit has to be on the current branch, and only on the current branch !!
# 
# Usage example:
#
# 1. Set commit 0c935403 date to now:
#
#   rewrite_commit_date 0c935403
#
# 2. Set commit 0c935403 date to 1402221655:
#
#   rewrite_commit_date 0c935403 1402221655
#
rewrite_commit_date () {
    local commit="$1" date_timestamp="$2"
    local date temp_branch="temp-rebasing-branch"
    local current_branch="$(git rev-parse --abbrev-ref HEAD)"

    if [[ -z "$date_timestamp" ]]; then
        date="$(date -R)"
    else
        date="$(date -R --date "@$date_timestamp")"
    fi

    git checkout -b "$temp_branch" "$commit"
    GIT_COMMITTER_DATE="$date" git commit --amend --date "$date"
    git checkout "$current_branch"
    git rebase "$commit" --onto "$temp_branch"
    git branch -d "$temp_branch"
}

1
Anda memiliki bug di sana: if [[ -z "$commit" ]]->if [[ -z "$date_timestamp" ]]
blueFast

Bagus! Saya akan merekomendasikan pengaturan GIT_COMMITTER_DATE=pada akhir metode untuk mencegah komitmen manual lebih lanjut untuk menjaga tanggal yang ditentukan.
loopkin

@loopkin, GIT_COMMITTER_DATE diset hanya untuk perintah "git commit" jadi tidak perlu menghapusnya setelah itu
nimrodm

@nimrodm, saya baru saja menguji lagi dan Anda benar. Terima kasih telah menunjukkannya.
loopkin

12

Untuk mengubah tanggal penulis dan tanggal komitmen:

GIT_COMMITTER_DATE="Wed Sep 23 9:40 2015 +0200" git commit --amend --date "Wed Sep 23 9:40 2015 +0200"

10

Jika Anda ingin mendapatkan tanggal pasti dari komit lain (katakanlah Anda rebase, edit komit dan ingin komit tersebut memiliki tanggal versi pra-rebase asli):

git commit --amend --date="$(git show -s --format=%ai a383243)"

Ini mengoreksi tanggal dari komitmen HEAD menjadi persis tanggal dari komitmen a383243 (termasuk lebih banyak digit jika ada ambiguitas). Ini juga akan memunculkan jendela editor sehingga Anda dapat mengedit pesan komit.

Itu untuk tanggal penulis yang biasanya Anda perhatikan - lihat jawaban lain untuk tanggal pengendara.


7

Jika Anda ingin melakukan jawaban yang diterima ( https://stackoverflow.com/a/454750/72809 ) di baris perintah Windows standar, Anda memerlukan perintah berikut:

git filter-branch -f --env-filter "if [ $GIT_COMMIT = 578e6a450ff5318981367fe1f6f2390ce60ee045 ]; then export GIT_AUTHOR_DATE='2009-10-16T16:00+03:00'; export GIT_COMMITTER_DATE=$GIT_AUTHOR_DATE; fi"

Catatan:

  • Dimungkinkan untuk membagi perintah ke beberapa baris (Windows mendukung pemisahan baris dengan simbol carret ^ ), tetapi saya tidak berhasil.
  • Anda dapat menulis tanggal ISO, menghemat banyak waktu menemukan hari-minggu yang tepat dan frustrasi umum atas urutan elemen.
  • Jika Anda ingin tanggal Penulis dan Pengemudi sama, Anda bisa mereferensikan variabel yang ditetapkan sebelumnya.

Terima kasih banyak untuk posting blog oleh Colin Svingen . Meskipun kodenya tidak berfungsi untuk saya, itu membantu saya menemukan solusi yang tepat.


7

Jika komit belum mendorong maka saya dapat menggunakan sesuatu seperti itu:

git commit --amend --date=" Wed Mar 25 10:05:44 2020 +0300"

setelah itu git bash membuka editor dengan tanggal yang sudah diterapkan sehingga Anda hanya perlu menyimpannya dengan mengetikkan mode perintah editor VI ": wq" dan Anda dapat mendorongnya


2
Hanya menambahkan ke jawaban yang bagus: jika Anda tidak ingin mengedit pesan komit (jika Anda hanya ingin mengubah tanggal komit), gunakan --no-editopsi.
Antonio Vinicius Menezes Medei

Selain itu, jika komit telah didorong, Anda masih dapat mendorong komit yang diubah menggunakan git push -f(pembaruan paksa). Itu mungkin memiliki efek samping. (terutama jika banyak orang memiliki klon repositori lokal)
Antonio Vinicius Menezes Medei


2

Sudah ada banyak jawaban bagus, tetapi ketika saya ingin mengubah tanggal untuk banyak komit dalam satu hari atau dalam satu bulan, saya tidak menemukan jawaban yang tepat. Jadi saya membuat skrip baru untuk ini dengan penjelasan, semoga akan membantu seseorang:

#!/bin/bash

# change GIT_AUTHOR_DATE for commit at Thu Sep 14 13:39:41 2017 +0800
# you can change the data_match to change all commits at any date, one day or one month
# you can also do the same for GIT_COMMITTER_DATE

git filter-branch --force --env-filter '

date_match="^Thu, 14 Sep 2017 13+"              

# GIT_AUTHOR_DATE will be @1505367581 +0800, Git internal format 
author_data=$GIT_AUTHOR_DATE;                   
author_data=${author_data#@}                  
author_data=${author_data% +0800}                # author_data is 1505367581     

oneday=$((24*60*60))

# author_data_str will be "Thu, 14 Sep 2017 13:39:41 +0800", RFC2822 format
author_data_str=`date -R -d @$author_data`      

if [[ $author_data_str =~ $date_match ]];
then
    # remove one day from author_data
    new_data_sec=$(($author_data-$oneday))
    # change to git internal format based on new_data_sec
    new_data="@$new_data_sec +0800"             
    export GIT_AUTHOR_DATE="$new_data"
fi
' --tag-name-filter cat -- --branches --tags

Tanggal akan diubah:

AuthorDate: Wed Sep 13 13:39:41 2017 +0800
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.