Bagaimana cara checkout di Git berdasarkan tanggal?

314

Saya sedang mengerjakan regresi dalam kode sumber. Saya ingin memberi tahu Git: "checkout sumber berdasarkan tanggal / waktu yang diparameterisasi". Apakah ini mungkin?

Saya juga telah melakukan perubahan pada tampilan saya saat ini yang tidak ingin saya hilangkan. Idealnya, saya ingin beralih antara sumber saat ini, dan beberapa versi saya tertarik berdasarkan tanggal sebelumnya.

Amir Afghani
sumber
9
Kalau-kalau Anda tidak tahu tentang itu, git bisect cukup bagus untuk menemukan regresi. Saya akan mengatakan, gunakan sintaks {1 tahun yang lalu} seperti kata Andy, untuk menemukan komit yang dikenal baik, lalu gunakan itu sebagai git bisect goodtitik awal Anda .
MatrixFrog
Saya merasa ini adalah kasus penggunaan yang bagus untuk tags.
Jess

Jawaban:

365

Untuk menjaga perubahan Anda saat ini

Anda dapat menyimpan pekerjaan Anda simpanan, tanpa melakukannya, dengan git stash. Anda akan menggunakan git stash popuntuk mendapatkannya kembali. Atau Anda dapat (seperti kata carleeto ) git commitke cabang terpisah.

Checkout berdasarkan tanggal menggunakan rev-parse

Anda dapat checkout komit dengan tanggal tertentu menggunakan rev-parseseperti ini:

git checkout 'master@{1979-02-26 18:30:00}'

Rincian lebih lanjut tentang opsi yang tersedia dapat ditemukan di git-rev-parse.

Seperti disebutkan dalam komentar, metode ini menggunakan reflog untuk menemukan komit dalam riwayat Anda. Secara default, entri ini kedaluwarsa setelah 90 hari . Meskipun sintaks untuk menggunakan reflog kurang verbose Anda hanya dapat kembali 90 hari.

Keluar berdasarkan tanggal menggunakan daftar rev

Opsi lain, yang tidak menggunakan reflog, adalah menggunakan rev-listuntuk mendapatkan komit pada titik waktu tertentu dengan:

git checkout `git rev-list -n 1 --first-parent --before="2009-07-27 13:37" master`

Catat --first-parent jika Anda hanya menginginkan riwayat dan bukan versi yang dibawa oleh gabungan. Itu yang biasanya Anda inginkan.

Andy
sumber
2
@Rocky Bisakah Anda memberi kami detail lebih lanjut Rocky? Apa yang Anda masukkan pada baris perintah dan mengapa Anda mengatakan itu tidak berfungsi? Apakah Anda menerima pesan kesalahan?
Andy
8
@ Rocky: Masalahnya adalah bahwa parameter perlu dilampirkan dalam tanda kutip, kalau tidak bash memisahkan argumen di spasi. Coba git co 'master@{2 days ago}'.
Mark Wilden
13
Catatan: tergantung pada seberapa jauh Anda pergi, ini mungkin tidak berfungsi karena menggunakan reflog (yang kedaluwarsa setelah beberapa waktu). Anda akan melihat 'peringatan: Log untuk' master 'hanya kembali ke ...'. Solusi Rocky akan selalu berhasil. git checkoutgit rev-list -n 1 --before="2009-07-27 13:37" master
Mark Nadig
3
Saya mengedit jawaban Anda karena backtick sudah usang dan sulit dibaca. Subshell $(...)lebih disukai.
Amedee Van Gasse
1
@Andy Selamat ulang tahun ke-40, Andy! (dengan asumsi itulah yang dimaksud 1979-02-26 :))
David Blevins
123

Solusi Andy tidak berhasil untuk saya. Di sini saya menemukan cara lain:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`

Git: checkout berdasarkan tanggal

Rocky
sumber
3
Ketika saya menjalankan perintah di atas, saya mendapatkan error: unknown switch `n'ide bagaimana mengatasi ini?
Tim
15

Sepertinya Anda memerlukan sesuatu seperti ini: Git checkout berdasarkan tanggal

Dengan kata lain, Anda menggunakan rev-listuntuk menemukan komit dan kemudian menggunakan checkout untuk benar-benar mendapatkannya.

Jika Anda tidak ingin kehilangan perubahan bertahap Anda, cara termudah adalah membuat cabang baru dan mengkomitnya ke cabang itu. Anda selalu dapat berpindah-pindah antar cabang.

Sunting: Tautan tidak aktif, jadi inilah perintahnya:

git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
Carl
sumber
2
Tautan bagus! Jadi git checkout branch@{date}berhentilah bekerja ketika reflog kedaluwarsa, tetapi Anda dapat menggunakannya git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`.
cdunn2001
10

Bagi mereka yang lebih suka pipa untuk memerintahkan substitusi

git rev-list -n1 --before=2013-7-4 master | xargs git checkout
Steven Penny
sumber
9

Dalam kasus saya -n 1opsi tidak berfungsi. Pada Windows saya menemukan bahwa urutan perintah berikut berfungsi dengan baik:

git rev-list -1 --before="2012-01-15 12:00" master

Ini mengembalikan SHA komit yang sesuai untuk tanggal yang diberikan, dan kemudian:

git checkout SHA
BartoszKP
sumber
4

The git rev-parsesolusi yang diusulkan oleh @ Andy bekerja dengan baik jika tanggal Anda tertarik adalah komit tanggal ini . Namun jika Anda ingin checkout berdasarkan tanggal penulis , rev-parsetidak akan berfungsi, karena tidak menawarkan opsi untuk menggunakan tanggal itu untuk memilih komit. Sebagai gantinya, Anda dapat menggunakan yang berikut ini.

git checkout $(
  git log --reverse --author-date-order --pretty=format:'%ai %H' master |
  awk '{hash = $4} $1 >= "2016-04-12" {print hash; exit 0 }
)

(Jika Anda juga ingin menentukan waktu penggunaan $1 >= "2016-04-12" && $2 >= "11:37"dalam predikat awk .)

Diomidis Spinellis
sumber
3

Melangkah lebih jauh dengan rev-listopsi, jika Anda ingin menemukan komit gabungan terbaru dari cabang master Anda ke cabang produksi Anda (sebagai contoh murni hipotetis):

git checkout `git rev-list -n 1 --merges --first-parent --before="2012-01-01" production`

Saya perlu menemukan kode yang ada di server produksi pada tanggal tertentu. Ini menemukannya untukku.

Egerlach
sumber
2

Jika Anda ingin dapat kembali ke versi repositori yang tepat pada saat Anda melakukan build, yang terbaik adalah menandai komit dari mana Anda membuat build.

Jawaban lain menyediakan teknik untuk mengembalikan repositori ke komit terbaru di cabang pada waktu tertentu - tetapi mereka mungkin tidak selalu cukup. Misalnya, jika Anda membangun dari cabang, dan kemudian menghapus cabang, atau membangun dari cabang yang kemudian direstrukturisasi, komit yang Anda bangun dapat menjadi "tidak terjangkau" di git dari cabang mana pun saat ini. Objek yang tidak terjangkau di git akhirnya dapat dihapus ketika repositori dipadatkan.

Menempatkan tag pada komit berarti tidak pernah menjadi tidak dapat dijangkau, apa pun yang Anda lakukan dengan cabang setelah itu (kecuali menghapus tag).

antlersoft
sumber
Meskipun ini tidak memberi saya jawaban yang saya cari, itu memang pantas disebut dengan baik karena menunjukkan aspek yang tidak disebutkan sejauh ini. Ini bisa menjadi sumber masalah yang mencegah Anda mencapai versi yang tepat.
manuelvigarcia
1
git rev-list -n 1 --before="2009-07-27 13:37" origin/master

ambil string yang dicetak (misalnya XXXX) dan lakukan:

git checkout XXXX
Luca C.
sumber
2
Bukankah ini duplikat dari jawaban @bartoszkp? hanya menambahkan referensi ke asal, harus menjadi komentar pada jawaban yang lain ...
manuelvigarcia
ya, pada kenyataannya hampir, hanya menjelaskan apa yang akan disalin untuk siapa yang tidak tahu apa SHA (seperti saya), dalam kasus saya bahwa teks tidak jelas dan ini adalah kode saya setelah menemukan solusi, tidak disalin, sebenarnya Anda dapat melihat pilihannya juga sedikit berbeda
Luca C.