Bagaimana cara mengambil satu file dari revisi tertentu di Git?

832

Saya memiliki repositori Git dan saya ingin melihat bagaimana beberapa file terlihat beberapa bulan yang lalu. Saya menemukan revisi pada tanggal itu; itu 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8. Saya perlu melihat seperti apa satu file itu, dan juga menyimpannya sebagai file ("baru").

Saya berhasil melihat file menggunakan gitk, tetapi tidak memiliki opsi untuk menyimpannya. Saya mencoba dengan alat baris perintah, yang paling dekat yang saya dapatkan adalah:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

Namun, perintah ini menunjukkan perbedaan, dan bukan isi file. Saya tahu nantinya saya bisa menggunakan sesuatu seperti PAGER=catdan mengarahkan output ke file, tetapi saya tidak tahu bagaimana untuk sampai ke konten file yang sebenarnya.

Pada dasarnya, saya mencari sesuatu seperti svn cat .

Milan Babuškov
sumber
73
Kuncinya di sini: git show(tidak membantu) menggunakan sintaks yang berbeda dengan titik dua. git show 2c7cf:my_file.txt
Steve Bennett
4
Untuk lebih memperjelas, perintah di atas adalah meminta git untuk menunjukkan dua objek terpisah, revisi dan file. Jawaban yang diterima di bawah ini, yang menggunakan titik dua antara dua item meminta file tertentu pada revisi tertentu.
jhclark
2
Pada * nix Anda tidak perlu PAGER, cukup shell redirection output dengan>
Konstantin Pelepelin
kemungkinan rangkap dari Apakah ada perintah git cepat untuk melihat versi lama suatu file?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
Checat memiliki komentar penting, bagi mereka yang ingin kontennya diekspor ke beberapa file. Anda memerlukan sesuatu seperti ini: git show {sha}: my_file.txt> old_my_file.txt
ormurin

Jawaban:

744

Untuk melengkapi jawaban Anda sendiri, sintaksnya memang

git show object
git show $REV:$FILE
git show somebranch:from/the/root/myfile.txt
git show HEAD^^^:test/test.py

Perintah ini menggunakan gaya revisi yang biasa, artinya Anda dapat menggunakan salah satu dari yang berikut ini:

  1. nama cabang (seperti yang disarankan oleh ash )
  2. HEAD+ x jumlah ^karakter
  3. Hash SHA1 dari revisi yang diberikan
  4. Beberapa (mungkin 5) karakter pertama dari hash SHA1 yang diberikan

Tip Penting untuk diingat bahwa ketika menggunakan " git show", selalu tentukan path dari root repositori , bukan posisi direktori Anda saat ini.

(Meskipun Mike Morearty menyebutkan bahwa, setidaknya dengan git 1.7.5.4, Anda dapat menentukan jalur relatif dengan meletakkan " ./" di awal jalur - misalnya:

git show HEAD^^:./test.py

)


Dengan Git 2.23+ (Agustus 2019), Anda juga dapat menggunakan perintahgit restore pengganti yang membingungkangit checkout

git restore -s <SHA1>     -- afile
git restore -s somebranch -- afile

Itu akan mengembalikan pada pohon yang bekerja hanya file yang ada di "source" ( -s) commit SHA1 atau cabang somebranch.
Untuk mengembalikan juga indeks:

git restore -s <SHA1> -SW -- afile

( -SW: kependekan dari --staged --worktree)


Sebelum git1.5.x, itu dilakukan dengan beberapa pipa ledeng:

git ls-tree <rev>
perlihatkan daftar satu atau lebih objek 'gumpalan' di dalam komit

git cat-file blob <file-SHA1>
cat file seperti yang telah dilakukan dalam revisi tertentu (mirip dengan svn cat). gunakan git ls-tree untuk mengambil nilai file-sha1 yang diberikan

git cat-file -p $(git-ls-tree $REV $file | cut -d " " -f 3 | cut -f 1)::

git-ls-tree mencantumkan ID objek untuk $ file dalam revisi $ REV, ini dipotong dari output dan digunakan sebagai argumen untuk git-cat-file, yang seharusnya benar-benar disebut git-cat-objek, dan hanya membuang objek itu ke stdout.


Catatan: sejak Git 2.11 (Q4 2016), Anda dapat menerapkan filter konten ke git cat-fileoutput!

Lihat komit 3214594 , komit 7bcf341 (09 Sep 2016), komit 7bcf341 (09 Sep 2016), dan komi b9e62f6 , komit 16dcc29 (24 Agu 2016) oleh Johannes Schindelin ( dscho) .
(Digabung oleh Junio ​​C Hamano - gitster- dalam komit 7889ed2 , 21 Sep 2016)

cat-file: dukungan --textconv/ --filtersdalam mode batch

Meskipun " git hash-objects", yang merupakan alat untuk mengambil aliran data sistem file dan memasukkannya ke toko objek Git, diizinkan untuk melakukan konversi "luar-dunia-ke-Git" (mis. Konversi dan aplikasi akhir-line dari clean-filter), dan memiliki fitur aktif secara default sejak awal, " git cat-file" operasi terbalik , yang mengambil objek dari penyimpanan objek Git dan mengeksternalisasi untuk konsumsi oleh dunia luar, tidak memiliki mekanisme yang setara untuk jalankan "Git-to-outside-world"

git config diff.txt.textconv "tr A-Za-z N-ZA-Mn-za-m <"
git cat-file --textconv --batch

Catatan: " git cat-file --textconv" mulai melakukan segmentasi baru-baru ini (2017), yang telah diperbaiki di Git 2.15 (Q4 2017)

Lihat komit cc0ea7c (21 Sep 2017) oleh Jeff King ( peff) .
(Digabung oleh Junio ​​C Hamano - gitster- di commit bfbc2fc , 28 Sep 2017)


Perhatikan bahwa untuk mengganti / mengganti file dengan konten yang lalu, Anda seharusnya tidak menggunakan perintah yang membingungkangit checkout lagi, tetapi git restore(Git 2.23+, Agustus 2019)

git restore -s <SHA1> -- afile

Itu akan mengembalikan pada pohon yang bekerja hanya file yang ada di "source" ( -s) commit SHA1.
Untuk mengembalikan juga indeks:

git restore -s <SHA1> -SW -- afile

( -SW: kependekan dari --staged --worktree)

VONC
sumber
6
@Oscar karena git showpada dasarnya membuang konten pada stdout(output standar), Anda bisa mengarahkan ulang output itu ke file apa pun yang Anda inginkan ( tldp.org/LDP/abs/html/io-redirection.html ).
VonC
8
git checkout [branch | revision] filepathadalah perintah yang tepat
Gaui
12
@Gaui tetapi git checkoutakan mengganti file Anda dengan versi lain, yang bertentangan git show, yang memungkinkan Anda untuk menyimpannya dengan nama yang berbeda, agar Anda dapat melihat dan melihat keduanya (versi saat ini dan versi lama). Tidak jelas dari pertanyaan apakah OP ingin mengganti versi saat ini dengan yang lama.
VonC
9
Saya ingin mencatat bahwa ^^^juga dapat ditulis lebih umum sebagai ~~~atau, lebih baik ~3,. Menggunakan tilde juga memiliki keuntungan tidak memicu pencocokan nama file dari beberapa shell (zsh, misalnya).
Eric O Lebigot
2
Saya tidak memiliki git yang cukup lama untuk memeriksa: apakah pre-1.5.x git rev-parsemenangani rev:pathsintaks? (Dalam git yang lebih baru Anda bisa git cat-file -p $REV:path. Namun, git showbekerja untuk jalur direktori juga, jadi ini bukan hanya lebih pendek, biasanya lebih dekat dengan apa yang diinginkan.)
torek
510

Jika Anda ingin mengganti / menimpa konten file di cabang Anda saat ini dengan konten file dari komit sebelumnya atau cabang lain, Anda dapat melakukannya dengan perintah ini:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

atau

git checkout mybranchname path/to/file.txt

Anda kemudian harus melakukan perubahan itu agar efektif di cabang saat ini.

ca
sumber
4
solusi paling sederhana dan inilah tujuan dari git-checkout - untuk menentukan pathname berarti hanya file yang cocok yang diperiksa. Dari halaman manual git-checkout: master checkout git ~ 2 Makefile
RichVel
1
Lalu, bagaimana Anda kembali ke keadaan sebelumnya sebelum Anda menjalankan perintah ini?
Flint
@ Flint jika Anda berasal dari negara HEAD itu akan sesederhana git checkout HEAD - [path lengkap].
Tiago Espinha
72
Perhatikan bahwa ini menimpa file yang ada di jalur itu, sedangkan git show SHA1:PATHsolusinya hanya mencetak ke stdout.
Flimm
Bagus! Saya tidak akan bisa memecahkan masalah ini dengan melihat git help checkout. Saya harus checkout subdirektori pada tanggal tertentu, dan menggunakan pendekatan ini, saya bisa membuat sintaks ini berfungsi:git checkout @{YYYY-MM-DD} sub-dir
haridsv
150

Anda perlu memberikan path lengkap ke file:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt
Milan Babuškov
sumber
7
tidak harus jalur penuh. Jalan dari direktori git root (mereka yang datang git show --name-onlysudah cukup juga
Mohsen
7
Eh, path lengkap dari root repositori. Lihatlah contoh yang saya berikan. Tidak ada garis miring sebelum "penuh".
Milan Babuškov
7
FYI, jika Anda berada dalam subdir, Anda dapat menggunakan ./filename.ext juga.
Traveler
Saya pikir intinya adalah, jika Anda masuk full/repo/path/todan mencoba:, git show 27cf8e84:my_file.txtAnda akan dihargai dengan pesan seperti: fatal: Path 'full / repo / path / ke / my_file.txt' ada, tetapi bukan 'my_file.txt' . Apakah maksud Anda '27cf8e84: full / repo / path / to / my_file.txt' alias '27cf8e84: ./ my_file.txt'? Ini seperti, Git bisa membantu secara langsung, tetapi memilih untuk menjadi jagoan disini.
Ed Randall
101

Cara termudah adalah menulis:

git show HASH:file/path/name.ext > some_new_name.ext

dimana:

  • HASH adalah revisi hash nomor hash SHA-1
  • file / path / name.ext adalah nama file yang Anda cari
  • some_new_name.ext adalah path dan nama tempat file lama harus disimpan

Contoh

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:my_file.txt > my_file.txt.OLD

Ini akan menyimpan my_file.txt dari revisi 27cf8e sebagai file baru dengan nama my_file.txt.OLD

Itu diuji dengan Git 2.4.5.

Jika Anda ingin mengambil file yang dihapus, Anda dapat menggunakan HASH~1(satu komit sebelum HASH yang ditentukan).

CONTOH:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt
Jmarceli
sumber
1
Info Tambahan: Anda bisa mendapatkan HASH misalnya dengan git log
xotix
@xotix Terima kasih. Saya mendapatkan semua riwayat HASH untuk file tertentu menggunakangit log file/path/name.ext
Sriram Kannan
11

Di Windows, dengan Git Bash:

  • di ruang kerja Anda, ubah dir ke folder tempat file Anda berada
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext
Alessandro Jacopson
sumber
8

Dan untuk membuangnya ke file (setidaknya untuk Windows) - Git Bash:

$ echo "`git show 60d8bdfc:src/services/LocationMonitor.java`" >> LM_60d8bdfc.java

The "kutipan diperlukan sehingga mempertahankan baris.

Mr_and_Mrs_D
sumber
Bagus +1. Tambahan yang bagus pada git showsintaks yang saya sebutkan di atas.
VonC
23
Saya benar-benar tidak mengerti mengapa Anda menggunakan gema, dengan atau tanpa tanda kutip. Dan saya tidak mengerti mengapa Anda ingin menambahkan bentuk redirection output. Bukankah lebih baik menulis: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java Jika karena alasan tertentu Anda benar-benar ingin memaksakan akhiran gaya dos, Anda dapat menyalurkannya melalui unix2dos. Tapi saya tidak pernah menemukan itu sedikit pun berguna untuk mempertahankan dos baris-akhir pada Windows, karena alat teks apa pun selain notepad yang saya gunakan pada Windows menangani garis-garis unix dengan baik.
sootsnoot
4
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java bekerja untuk saya.
Mike6679
@ Mike: apakah Anda di windows?
Mr_and_Mrs_D
2
jangan gunakan tanda kutip ganda karena jika karakter file Anda yang terlihat seperti variabel shell, yaitu $ LANG, itu akan diganti. @ LưuVĩnhPhúc adalah penghemat. juga jangan gunakan >> Ini akan menambahkan file jika ada dan mungkin menyebabkan kesalahan
theguy
3

Ini akan membantu Anda mendapatkan semua file yang terhapus di antara commit tanpa menentukan path, berguna jika ada banyak file yang dihapus.

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1
Adrian Gunawan
sumber
1
git checkout {SHA1} -- filename

perintah ini mendapatkan file yang disalin dari komit tertentu.

jsina
sumber
-2

Dapatkan file dari komit sebelumnya melalui memeriksa-komit sebelumnya dan menyalin file.

  • Perhatikan cabang mana Anda berada: cabang git
  • Lihat komit sebelumnya yang Anda inginkan: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • Salin file yang Anda inginkan ke lokasi sementara
  • Periksa cabang tempat Anda mulai: git checkout theBranchYouNoted
  • Salin dalam file yang Anda tempatkan di lokasi sementara
  • Komit perubahan Anda untuk git: git commit -m "added file ?? from previous commit"
rocketInABog
sumber