วิธีการดึงไฟล์เดียวจากการแก้ไขเฉพาะใน Git?


831

ฉันมีที่เก็บ Git และฉันต้องการดูว่าบางไฟล์ดูเมื่อไม่กี่เดือนที่ผ่านมา ฉันพบการแก้ไขในวันนั้น 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8มันเป็น ฉันต้องการดูว่าไฟล์หนึ่งมีลักษณะอย่างไรและยังบันทึกเป็นไฟล์ ("ใหม่")

ฉันจัดการเพื่อดูไฟล์โดยใช้gitkแต่มันไม่มีตัวเลือกให้บันทึก ฉันลองใช้เครื่องมือบรรทัดคำสั่งสิ่งที่ใกล้เคียงที่สุดคือ:

git-show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8 my_file.txt

อย่างไรก็ตามคำสั่งนี้แสดงส่วนต่างและไม่ใช่เนื้อหาไฟล์ ฉันรู้ว่าฉันสามารถใช้สิ่งที่ชอบPAGER=catและเปลี่ยนเส้นทางผลลัพธ์ไปยังไฟล์ในภายหลังได้แต่ฉันไม่รู้ว่าจะไปยังเนื้อหาไฟล์จริงได้อย่างไร

โดยทั่วไปฉันกำลังมองหาสิ่งที่ชอบแมว SVN


73
กุญแจที่นี่: git show(ไม่ช่วยเหลือ) ใช้ไวยากรณ์ต่างกับโคลอน git show 2c7cf:my_file.txt
Steve Bennett

4
เพื่อชี้แจงเพิ่มเติมคำสั่งข้างต้นจะขอให้คอมไพล์แสดงวัตถุที่แยกกันสองรายการการแก้ไขและไฟล์ คำตอบที่ได้รับการยอมรับด้านล่างซึ่งใช้เครื่องหมายโคลอนระหว่างสองรายการกำลังขอไฟล์ที่ระบุเฉพาะในการแก้ไขเฉพาะ
jhclark

2
ใน * ระวังคุณไม่จำเป็นต้องใช้ PAGER เพียงแค่เปลี่ยนเส้นทางการส่งออกด้วย>
Konstantin Pelepelin


Checat มีความคิดเห็นที่สำคัญสำหรับผู้ที่ต้องการส่งออกเนื้อหาไปยังไฟล์บางไฟล์ คุณต้องการอะไรเช่นนี้: git show {sha}: my_file.txt> old_my_file.txt
ormurin

คำตอบ:


743

เพื่อให้คำตอบของคุณสมบูรณ์ไวยากรณ์นั้นแน่นอน

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

คำสั่งใช้รูปแบบการแก้ไขตามปกติซึ่งหมายความว่าคุณสามารถใช้สิ่งใดสิ่งหนึ่งต่อไปนี้:

  1. ชื่อสาขา (ที่แนะนำโดยเถ้า )
  2. HEAD+ x จำนวน^อักขระ
  3. แฮช SHA1 ของการแก้ไขที่กำหนด
  4. อักขระสองสามตัวแรก (อาจ 5) ของแฮช SHA1 ที่กำหนด

เคล็ดลับสิ่งสำคัญคือต้องจำไว้ว่าเมื่อใช้ " git show" ให้ระบุพา ธ จากรูทของที่เก็บเสมอไม่ใช่ตำแหน่งไดเรกทอรีปัจจุบันของคุณ

(แม้ว่าMike Moreartyกล่าวว่าอย่างน้อยด้วย git 1.7.5.4 คุณสามารถระบุเส้นทางสัมพัทธ์ได้โดยใส่ " ./" ที่จุดเริ่มต้นของเส้นทาง - ตัวอย่างเช่น:

git show HEAD^^:./test.py

)


ด้วย Git 2.23+ (สิงหาคม 2019) คุณสามารถใช้git restore ซึ่งแทนที่คำสั่งที่สับสนgit checkout

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

ที่จะเรียกคืนบนต้นทำงานเฉพาะไฟล์ที่อยู่ใน"ต้นฉบับ" ( -s)กระทำ SHA1 somebranchหรือสาขา
ในการกู้คืนดัชนีด้วย:

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

( -SW: สั้นสำหรับ--staged --worktree )


ก่อน git1.5.x นั่นทำด้วยระบบประปาบางส่วน:

git ls-tree <rev>
แสดงรายการวัตถุ 'หยด' ตั้งแต่หนึ่งวัตถุขึ้นไปภายในการคอมมิท

git cat-file blob <file-SHA1>
แมวไฟล์ตามที่ได้รับมอบหมายภายในการแก้ไขที่เฉพาะเจาะจง (คล้ายกับ svn cat) ใช้ git ls-tree เพื่อดึงค่าของไฟล์ที่กำหนด sha1

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

git-ls-tree แสดง ID อ็อบเจ็กต์สำหรับ $ file ในการแก้ไข $ REV ซึ่งถูกตัดออกจากเอาต์พุตและใช้เป็นอาร์กิวเมนต์สำหรับ git-cat-file ซึ่งควรจะเรียกว่า git-cat-object จริงๆ วัตถุนั้นจะ stdout


หมายเหตุ: ตั้งแต่ Git 2.11 (ไตรมาสที่ 4 ปี 2559) คุณสามารถใช้ตัวกรองเนื้อหากับgit cat-fileเอาท์พุท!

ดูกระทำ 3214594 , กระทำ 7bcf341 (9 กันยายน 2016) กระทำ 7bcf341 (9 กันยายน 2016) และกระทำ b9e62f6 , กระทำ 16dcc29 (24 สิงหาคม 2016) โดยโยฮันเน Schindelin (dscho )
(ผสานโดยJunio ​​C Hamano - gitster- in 7889ed2 , 21 Sep 2016)

cat-file: การสนับสนุน--textconv/--filtersในโหมดแบทช์

แม้ว่า " git hash-objects" ซึ่งเป็นเครื่องมือที่ใช้สตรีมข้อมูลระบบไฟล์และวางลงในที่เก็บวัตถุ Git อนุญาตให้ทำการแปลง "นอกโลกสู่ Git" (เช่นการแปลงและแอปพลิเคชันปลายทาง ของตัวกรองที่สะอาด) และมันมีคุณสมบัติตามค่าเริ่มต้นจากวันแรก ๆ การดำเนินการย้อนกลับ " git cat-file" ซึ่งใช้วัตถุจากที่เก็บวัตถุ Git และส่งออกเพื่อการบริโภคโดยโลกภายนอกไม่มีกลไกที่เทียบเท่ากับ ใช้งาน "Git เพื่อนอกโลก"

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

หมายเหตุ: " git cat-file --textconv" เริ่ม segfaulting เมื่อเร็ว ๆ นี้ (2017) ซึ่งได้รับการแก้ไขใน Git 2.15 (Q4 2017)

ดูการกระทำ cc0ea7c (21 Sep 2017) โดยJeff King ( peff) )
(ผสานโดยJunio ​​C Hamano - gitster- in bfbc2fc , 28 Sep 2017)


สังเกตได้ว่า แทนที่ / แทนที่ไฟล์ด้วยเนื้อหาที่ผ่านมาคุณไม่ควรใช้คำสั่งที่สับสนgit checkoutอีกต่อไป แต่git restore(Git 2.23+, สิงหาคม 2019)

git restore -s <SHA1> -- afile

ที่จะคืนค่าในแผนผังการทำงานเฉพาะไฟล์ที่มีอยู่ใน "แหล่งที่มา" ( -s) กระทำ SHA1
ในการกู้คืนดัชนีด้วย:

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

(-SW : สั้นสำหรับ--staged --worktree )


6
@Oscar เนื่องจากการgit showดัมพ์เนื้อหาบนstdout(เอาต์พุตมาตรฐาน) คุณสามารถเปลี่ยนทิศทางเอาต์พุตไปยังไฟล์ใด ๆ ที่คุณต้องการ ( tldp.org/LDP/abs/html/io-redirection.html )
VonC

8
git checkout [branch | revision] filepathเป็นคำสั่งที่ถูกต้อง
Gaui

12
@Gaui แต่git checkoutจะแทนที่ไฟล์ของคุณด้วยเวอร์ชันอื่นซึ่งตรงข้ามกับgit showที่อนุญาตให้คุณบันทึกไว้ภายใต้ชื่ออื่นเพื่อให้คุณได้รับและดูทั้งสอง (เวอร์ชันปัจจุบันและเวอร์ชันเก่า) มันไม่ชัดเจนจากคำถามว่า OP ต้องการแทนที่เวอร์ชันปัจจุบันด้วยอันเก่าหรือไม่
VonC

9
ผมอยากจะทราบว่า^^^ยังสามารถเขียนได้มากขึ้นโดยทั่วไปว่าเป็นหรือดีกว่า~~~ ~3การใช้เครื่องหมายตัวหนอนยังมีข้อได้เปรียบที่จะไม่กระตุ้นการจับคู่ชื่อไฟล์ของเชลล์บางตัว (เช่น zsh เป็นต้น)
Eric O Lebigot

2
ฉันไม่มี git เก่าเพียงพอที่จะตรวจสอบ: pre-1.5.x git rev-parseจัดการกับrev:pathไวยากรณ์หรือไม่ (ในคอมไพล์ล่าสุดที่คุณสามารถทำได้git cat-file -p $REV:pathอย่างไรก็ตามgit showใช้ได้กับพา ธ ของไดเรกทอรีด้วยดังนั้นจึงไม่สั้นกว่าปกติโดยทั่วไปจะใกล้เคียงกับที่ต้องการมากที่สุด)
torek

510

หากคุณต้องการแทนที่ / เขียนทับเนื้อหาของไฟล์ในสาขาปัจจุบันของคุณด้วยเนื้อหาของไฟล์จากการกระทำก่อนหน้าหรือสาขาที่แตกต่างกันคุณสามารถทำได้ด้วยคำสั่งเหล่านี้:

git checkout 08618129e66127921fbfcbc205a06153c92622fe path/to/file.txt

หรือ

git checkout mybranchname path/to/file.txt

จากนั้นคุณจะต้องยอมรับการเปลี่ยนแปลงเหล่านั้นเพื่อให้การเปลี่ยนแปลงมีผลในสาขาปัจจุบัน


4
ทางออกที่ง่ายที่สุดและนี่คือสิ่งที่ git-checkout ได้รับการออกแบบมา - การระบุชื่อพา ธ หมายถึงเฉพาะไฟล์ที่ตรงกันเท่านั้น จากหน้าคน git-checkout: git checkout master ~ 2 Makefile
RichVel

1
จากนั้นคุณจะกลับไปยังสถานะก่อนหน้าก่อนที่จะเรียกใช้คำสั่งนี้ได้อย่างไร
ฟลินท์

@ ฟลินท์ถ้าคุณมาจาก HEAD state มันจะง่ายเหมือนการเอา git checkout HEAD - [full path]
Tiago Espinha

72
โปรดทราบว่าสิ่งนี้จะเขียนทับไฟล์ที่มีอยู่ในพา ธ นั้นในขณะที่git show SHA1:PATHโซลูชันจะพิมพ์ไปยัง stdout เท่านั้น
Flimm

ดี! git help checkoutฉันจะไม่ได้รับสามารถที่จะคิดออกนี้โดยดูที่ ผมต้องชำระเงินไดเรกทอรีย่อย ณ วันที่กำหนดและการใช้วิธีการนี้ฉันจะได้รับรูปแบบนี้ทำงาน:git checkout @{YYYY-MM-DD} sub-dir
haridsv

150

คุณต้องระบุเส้นทางแบบเต็มไปยังไฟล์:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8:full/repo/path/to/my_file.txt

7
ไม่จำเป็นต้องเป็นเส้นทางที่สมบูรณ์ เส้นทางจากไดเรกทอรีรากคอมไพล์ (ผู้ที่เข้ามาgit show --name-onlyก็เพียงพอแล้ว
Mohsen

7
เอ่อเส้นทางเต็มจากที่เก็บราก ลองดูตัวอย่างที่ดีกว่านี้สิ ไม่มีเครื่องหมายทับก่อน "เต็ม"
มิลานBabuškov

7
หากคุณอยู่ในเขตย่อยคุณสามารถใช้. / ไฟล์ชื่อสำเร็จได้เช่นกัน
นักเดินทาง

ฉันคิดว่าประเด็นคือถ้าคุณอยู่ในfull/repo/path/toและคุณลอง: git show 27cf8e84:my_file.txtคุณจะได้รับรางวัลเช่นข้อความ: ร้ายแรง: เส้นทาง 'เต็ม / repo / เส้นทาง / ถึง / my_file.txt' มีอยู่ แต่ไม่ใช่ 'my_file.txt' . คุณหมายถึง '27cf8e84: full / repo / path / to / my_file.txt' aka '27cf8e84: ./ my_file.txt' หรือไม่ มันเหมือน Git สามารถช่วยโดยตรง แต่เลือกที่จะอวดความรู้ที่นี่
Ed Randall

101

ง่ายที่สุดวิธีคือการเขียน:

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

ที่อยู่:

  • HASHคือหมายเลขแฮชการแก้ไข Git SHA-1
  • file / path / name.extเป็นชื่อของไฟล์ที่คุณต้องการ
  • some_new_name.extเป็นพา ธ และชื่อที่ควรบันทึกไฟล์เก่า

ตัวอย่าง

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

นี่จะบันทึกmy_file.txtจากการแก้ไข27cf8eเป็นไฟล์ใหม่ที่มีชื่อ my_file.txt.OLD

ได้รับการทดสอบด้วย Git 2.4.5

หากคุณต้องการดึงไฟล์ที่ถูกลบคุณสามารถใช้HASH~1 (หนึ่งการกระทำก่อนที่แฮชที่ระบุ)

ตัวอย่าง:

git show 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8~1:deleted_file.txt > deleted_file.txt

1
ข้อมูลเพิ่มเติม: คุณสามารถรับ HASH ได้เช่นกับ git log
xotix

@xotix ขอบคุณ ฉันได้รับประวัติแฮชทั้งหมดสำหรับไฟล์หนึ่งไฟล์โดยใช้git log file/path/name.ext
Sriram Kannan

11

ใน Windows ด้วย Git Bash:

  • ในพื้นที่ทำงานของคุณเปลี่ยน dir เป็นโฟลเดอร์ที่ไฟล์ของคุณอยู่
  • git show cab485c83b53d56846eb883babaaf4dff2f2cc46:./your_file.ext > old.ext

8

และจะทิ้งลงในไฟล์ (อย่างน้อยใน Windows) - Git Bash:

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

"คำพูดที่มีความจำเป็นเพื่อที่จะเก็บรักษาการขึ้นบรรทัดใหม่


ทำได้ดีนี่. +1 นอกจากนี้ที่ดีในgit showไวยากรณ์ที่ฉันพูดถึงข้างต้น
VonC

23
ฉันไม่เข้าใจจริงๆว่าทำไมคุณถึงใช้เสียงสะท้อนไม่ว่าจะมีหรือไม่มีคำพูด และฉันไม่เข้าใจว่าทำไมคุณจึงต้องการรูปแบบการเปลี่ยนเส้นทางแบบต่อท้าย มันคงจะดีกว่าถ้าเขียน: git show 60d8bdfc: src / services / LocationMonitor.java> LM_60d8bdfc.java ด้วยเหตุผลบางอย่างที่คุณต้องการบังคับให้จบบรรทัดสไตล์ DOS คุณสามารถส่งผ่าน unix2dos ได้ แต่ฉันไม่เคยพบว่ามันมีประโยชน์น้อยที่สุดในการรักษาจุดสิ้นสุดของเส้นดอสบน Windows เช่นเดียวกับเครื่องมือข้อความอื่น ๆ ที่ไม่ใช่ notepad ที่ฉันใช้บน Windows จัดการกับเส้นแบบยูนิกซ์ได้ดี
sootsnoot

4
git show 60d8bdfc: src / services / LocationMonitor.java >> LM_60d8bdfc.java ทำงานให้ฉัน
Mike6679

@ ไมค์: คุณอยู่บน windows?
Mr_and_Mrs_D

2
อย่าใช้เครื่องหมายคำพูดคู่เพราะถ้าไฟล์ของคุณมีลักษณะคล้ายตัวแปรเชลล์เช่น $ LANG มันจะถูกแทนที่ @ LưuVĩnhPhúcประหยัด ยังไม่ได้ใช้ >> มันจะผนวกไฟล์ถ้ามันมีอยู่และอาจนำไปสู่ข้อผิดพลาด
theguy

3

การทำเช่นนี้จะช่วยให้คุณได้รับไฟล์ที่ถูกลบทั้งหมดระหว่างการคอมมิทโดยไม่ระบุพา ธ ซึ่งมีประโยชน์หากมีการลบไฟล์จำนวนมาก

git diff --name-only --diff-filter=D $commit~1 $commit | xargs git checkout $commit~1

1
git checkout {SHA1} -- filename

คำสั่งนี้รับไฟล์ที่คัดลอกจากการคอมมิทที่ระบุ


-2

รับไฟล์จากการคอมมิชชันก่อนหน้าผ่านการเช็กเอาต์การคอมมิทและการคัดลอกไฟล์ก่อนหน้า

  • โปรดทราบว่าคุณอยู่สาขาใด: git branch
  • ชำระเงินการกระทำก่อนหน้านี้ที่คุณต้องการ: git checkout 27cf8e84bb88e24ae4b4b3df2b77aab91a3735d8
  • คัดลอกไฟล์ที่คุณต้องการไปยังตำแหน่งชั่วคราว
  • ชำระเงินสาขาที่คุณเริ่มต้นจาก: git checkout theBranchYouNoted
  • คัดลอกไฟล์ที่คุณวางไว้ในตำแหน่งชั่วคราว
  • ยอมรับการเปลี่ยนแปลงของคุณเป็น git: git commit -m "added file ?? from previous commit"
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.