เป็นไปได้หรือไม่ที่จะผลัก git stash ไปยัง repository ระยะไกล?


205

ในคอมไพล์เป็นไปได้หรือไม่ที่จะสร้างที่ซ่อนผลักที่เก็บไปยังที่เก็บระยะไกลเรียกคืนที่ซ่อนอยู่ในคอมพิวเตอร์เครื่องอื่นและใช้ที่เก็บ?

หรือเป็นตัวเลือกของฉัน:

  • สร้างโปรแกรมปะแก้และคัดลอกโปรแกรมแก้ไขไปยังคอมพิวเตอร์เครื่องอื่นหรือ
  • สร้างสาขาย่อยและส่งมอบงานที่ไม่สมบูรณ์ให้สาขานั้นใช่ไหม

คำตอบ:


68

เป็นไปไม่ได้ที่จะนำมาใช้ผ่านการดึงข้อมูลหรือดังนั้น refspec มิเรอร์คือfetch = +refs/*:refs/*และแม้ว่าจะซ่อนrefs/stashมันจะไม่ถูกส่ง ชัดเจนrefs/stash:refs/stashไม่มีผลเช่นกัน!

มันจะสร้างความสับสนอยู่ดีเนื่องจากจะไม่ดึงข้อมูลทั้งหมดออกมา แต่เป็นข้อมูลล่าสุดเท่านั้น รายการ stashes เป็นreflogrefs/stashesของโทษ


4
คุณสามารถดึงที่ซ่อนล่าสุดจากรีโมตคอมไพล์ แต่ไม่สามารถซ่อนที่เก็บของคุณได้ สิ่งที่ต้องการ แต่คุณไม่สามารถรับการหยุดทำงานที่เก่ากว่าได้เนื่องจากมีการจัดเก็บไว้ใน reflog ที่ไม่สามารถดึงข้อมูลได้ ดูstackoverflow.com/questions/2248680/…git fetch some-remote +refs/stash:refs/remotes/some-remote/stashgit stash apply some-remote/stash
sj26

75

หมายเหตุ:ฉันเพิ่งเขียนคำตอบนี้ใหม่พร้อมกับ git-fu อีก 24 ชั่วโมงใต้เข็มขัดของฉัน :) ในประวัติศาสตร์เชลล์ตอนนี้ shebang ทั้งหมดกลายเป็นหนึ่งในสามสมุทร อย่างไรก็ตามฉันไม่ จำกัด สิทธิ์เพื่อความสะดวกของคุณ

ด้วยวิธีนี้ฉันหวังว่าคุณจะสามารถเห็นว่าฉันทำสิ่งต่าง ๆ ได้อย่างไรแทนที่จะต้องคัดลอกหรือวางสิ่งของอย่างสุ่มสี่สุ่มห้า


นี่คือขั้นตอน

สมมติว่าเป็นแหล่งที่มาใน ~ / OLDREPO ที่มีการหยุดทำงาน สร้างโคลนทดสอบที่ไม่มีการชน:

cd ~/OLDREPO
git clone . /tmp/TEST

ผลัก stashes ทั้งหมดเป็นสาขาชั่วคราว:

git send-pack /tmp/TEST $(for sha in $(git rev-list -g stash); \
    do echo $sha:refs/heads/stash_$sha; done)

วนรอบจุดสิ้นสุดการรับเพื่อแปลงกลับเป็นสถานะหยุดพัก:

cd /tmp/TEST/
for a in $(git rev-list --no-walk --glob='refs/heads/stash_*'); 
do 
    git checkout $a && 
    git reset HEAD^ && 
    git stash save "$(git log --format='%s' -1 HEAD@{1})"
done

ล้างสาขาชั่วคราวของคุณถ้าคุณจะ

git branch -D $(git branch|cut -c3-|grep ^stash_)

ทำรายการที่ซ่อนคอมไพล์แล้วคุณจะได้สิ่งนี้:

stash@{0}: On (no branch): On testing: openmp import
stash@{1}: On (no branch): On testing: zfsrc
stash@{2}: On (no branch): WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue
stash@{3}: On (no branch): WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{4}: On (no branch): WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{5}: On (no branch): WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{6}: On (no branch): WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{7}: On (no branch): WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{8}: On (no branch): WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{9}: On (no branch): WIP on emmanuel: bee6660 avoid unrelated changes

บนที่เก็บต้นฉบับดูเหมือนกัน

stash@{0}: WIP on emmanuel: bee6660 avoid unrelated changes
stash@{1}: WIP on testing: 28716d4 fixed implicit declaration of stat64
stash@{2}: WIP on xattrs: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{3}: WIP on testing: db9f77e fuse_unmount_all could be starved for the mtx lock
stash@{4}: WIP on testing: 3972694 removed braindead leftover -O0 flag
stash@{5}: WIP on xattrs: 3972694 removed braindead leftover -O0 flag
stash@{6}: WIP on debian-collab: c5c8037 zfs_pool_alert should be installed by default
stash@{7}: WIP on sehe: 7006283 fixed wrong path to binary in debianized init script (reported as part of issue #57)
stash@{8}: On testing: zfsrc
stash@{9}: On testing: openmp import

1
ฉันเรียนรู้มากในเวลาน้อยและฉันรู้สึกว่าฉันควรจะใช้คำสั่งหลายวิธีในวิธีการก่อนหน้าของฉันซึ่งฉันจะพยายามทำในภายหลัง
sehe

9
สิ่งนี้ทำงานได้ดีสำหรับฉันยกเว้นว่าฉันต้องการ a git add .ก่อนgit stash save ...ขั้นตอนตั้งแต่git stashปฏิเสธที่จะซ่อนไฟล์ใหม่เว้นแต่ว่าพวกเขาจะถูกจัดฉาก นอกจากนี้การวางท่อผลลัพธ์git rev-list ...ผ่านการtacย้อนกลับลำดับของการหยุดเพื่อให้พวกเขาออกมาในลำดับเดียวกัน
Alan Krueger

1
@sehe สคริปต์ที่ยอดเยี่ยม !! สองข้อเสนอแนะ: 1) - ย้อนกลับรายการอ้างอิงสุดท้ายเพื่อให้การหยุดอยู่ในลำดับเดียวกันใน repo เป้าหมายเช่นเดียวกับต้นฉบับ 2) จบforลูปสุดท้ายด้วยgit branch -D stash_$a(ล้างข้อมูลในขณะที่ stashes ถูกสร้างขึ้น) เพื่อให้บางสิ่งผิดปกติและเราลองอีกครั้งเราจะไม่ประมวลผลการคอมมิชชันอีกครั้ง
Keith Robertson

1
ขอบคุณมากที่สละเวลาอธิบายสิ่งที่คุณทำแทน "เพียงแค่โพสต์โซลูชัน"
Marjan Venema

1
วิธีการแก้ปัญหาสามารถปรับปรุงเพิ่มเติมได้: หากคุณแทนที่git stash save "$(git log --format='%s' -1 HEAD@{1})"ด้วยgit update-ref --create-reflog -m "$(git show -s --format=%B $rev)" refs/stash $revคุณได้รับข้อความที่ซ่อนเดิม ( update-refคือสิ่งที่git stash saveอยู่เบื้องหลัง)
Sebastian Schrader

31

ฉันไปงานปาร์ตี้สายเล็ก ๆ น้อย ๆ แต่ฉันเชื่อว่าฉันพบบางสิ่งที่เหมาะกับฉันเกี่ยวกับเรื่องนี้และมันก็อาจเหมาะสำหรับคุณเช่นกันหากสถานการณ์ของคุณเหมือนหรือคล้ายกัน

ฉันกำลังทำงานกับคุณสมบัติในสาขาของตัวเอง สาขาไม่ได้ถูกรวมเข้ากับเจ้านายและผลักจนกว่าจะเสร็จสิ้นหรือฉันได้ทำไปแล้วว่ารู้สึกสบายใจที่จะแสดงต่อสาธารณะ ดังนั้นสิ่งที่ฉันทำเมื่อฉันต้องการถ่ายโอนการเปลี่ยนแปลงที่ไม่มีฉากไปยังคอมพิวเตอร์เครื่องอื่นคือ:

  • ส่งข้อความคอมมิทเช่น " [non-commit] FOR TRANSFER ONLY" ที่มีเนื้อหาที่คุณต้องการถ่ายโอน
  • ลงชื่อเข้าใช้คอมพิวเตอร์เครื่องอื่น
  • จากนั้นทำ:

    git pull ssh+git://<username>@<domain>/path/to/project/ rb:lb

    URL อาจแตกต่างกันสำหรับคุณหากคุณเข้าถึงที่เก็บของคุณในวิธีอื่น สิ่งนี้จะดึงการเปลี่ยนแปลงจาก URL นั้นจากรีโมตกิ่ง "rb" ไปยังโลคอลสาขา "lb" โปรดทราบว่าฉันมีเซิร์ฟเวอร์ ssh ทำงานบนคอมพิวเตอร์ของฉันเองและสามารถเข้าถึงที่เก็บได้ด้วยวิธีดังกล่าว

  • git reset HEAD^ (หมายถึง --mixed )

    สิ่งนี้จะรีเซ็ต HEAD ให้ชี้ไปที่สถานะก่อนที่จะกระทำ "[non-commit]"

จาก git-reset (1): "--mixed : รีเซ็ตดัชนี แต่ไม่ใช่แผนผังการทำงาน (เช่นไฟล์ที่ถูกเปลี่ยนแปลงจะถูกเก็บไว้ แต่ไม่ได้ทำเครื่องหมายเพื่อยอมรับ) [... ]"

ดังนั้นคุณจะมีการเปลี่ยนแปลงไฟล์ในท้ายที่สุด แต่ไม่มีข้อผูกมัดใด ๆ ที่จะทำให้คุณเชี่ยวชาญและไม่จำเป็นต้องซ่อน

อย่างไรก็ตามสิ่งนี้จะทำให้คุณต้องgit reset --hard HEAD^อยู่ในพื้นที่เก็บข้อมูลที่คุณสร้าง "[non-commit]" เนื่องจากการกระทำนั้นเป็นขยะ


นี่เป็นสิ่งที่สกปรกกว่ามากจากนั้นเพียงสร้างสาขาฟีเจอร์ใหม่จากนั้นจึงลบทิ้งในภายหลัง ....
แทกost

@ Taegost ขึ้นอยู่กับสภาพแวดล้อมของคุณฉันเดา อาจเป็นสิ่ง CI / CD การป้องกันเพียงแค่ผลักสาขาต้นน้ำทึกทักใจ แต่ใช่ขึ้นอยู่กับสิ่งที่คุณต้องการคุณอาจต้องการสร้างสาขาเพื่อทำสิ่งเดียวกันให้สำเร็จ
Victor Zamanian

22

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

สิ่งที่ดีสำหรับฉันคือการยอมรับรหัสที่กำลังดำเนินการของฉัน (ในสาขาที่ฉันกำลังทำงานคนเดียว) เมื่อฉันไปถึงคอมพิวเตอร์เครื่องอื่น ๆ ให้ดึงแล้วยกเลิกการกระทำด้วย:

git reset --soft HEAD^

ทำงานต่อไปตามที่คุณเคยมีเมื่อมีการเปลี่ยนแปลงที่ดำเนินอยู่ทั้งหมดไม่มีข้อผูกมัดและไม่มีการเปลี่ยนแปลง

หวังว่ามันจะช่วย


เมื่อฉันพยายามทำสิ่งนี้ Origin ยังคงรักษา Commit ซึ่งไม่ได้ผูกมัดไว้ ปิด แต่ไม่มีซิการ์ให้ฉัน
rezwits

@rezwits ใช่แล้วรีโมตเก็บไว้ แต่มันง่ายพอที่จะลบสาขาชั่วคราวออกจากจุดกำเนิด
เซอร์โรเบิร์ต

ตามความเป็นจริงนั่นคือสิ่งที่ฉันได้ทำ!
rezwits

19

ดูเหมือนจะมีกลอุบายที่เป็นระเบียบในการแก้ปัญหานี้ คุณสามารถใช้git diff > file.diff(และคอมมิตไฟล์) จากนั้นกู้คืนการเปลี่ยนแปลงโดยใช้git apply file.diff(จากที่ใดก็ได้) เพื่อให้ได้ผลลัพธ์เดียวกัน

นี่ก็อธิบายไว้ที่นี่เช่นกัน


5
หากคุณมีไฟล์ที่ไม่ได้ติดตาม: 1. เพิ่มคอมไพล์ 2. git diff HEAD> file.diff
trickpatty

การส่งข้อความถึงตัวคุณเองนั้นจะช่วยให้ไม่มีข้อผูกมัด / รอยเท้าบน repo เลย! (เช่น: บันทึกย่อถึงตัวเองผ่านแอปสัญญาณเดสก์ท็อป) หรืออีเมล
จอห์นมี

9

ฉันจะใช้วิธีที่สองแม้ว่าจะไม่มีความคิดว่าทำไมคุณไม่สามารถมอบให้กับสาขาหลัก / สาขาที่โดดเด่นได้ มันเป็นไปได้ที่จะทำการเก็บเชอร์รี่ด้วยเช่นกัน


27
ไม่มีเหตุผลทางเทคนิคที่จะไม่ผูกพันกับอาจารย์ / นักแสดง แต่เพียงว่าฉันต้องการพูดว่า "นี่ไม่ใช่ความมุ่งมั่นที่แท้จริง แต่เป็นเพียงการบันทึกงานของฉันเพื่อให้สามารถนำไปใช้กับเครื่องอื่น"
Andrew Grimm

4

AFAIK แนวคิดทั้งหมดของการซ่อนคือการซ่อนบางสิ่งที่ไม่สำคัญในพรมท้องถิ่น ไม่มีใครควรรู้เกี่ยวกับอึที่คุณชื่นชอบ ;-) เฉพาะ "แต่" คือ: แต่ถ้าฉันพัฒนาบนเวิร์กสเตชันสองคู่? ถ้าอย่างนั้นก็scpจะดีกว่า


9
สิ่งที่ตลกนี้ควรจะเป็นความคิดเห็น ;-)
Andrew Grimm

2
รวม git-ssh-newbie ที่นี่ แต่คุณสามารถใช้ scp กับ github ได้หรือไม่?
Koen

ไม่ส่วนหน้าของ git-ssh ของ github นั้นถูกตั้งโปรแกรมไว้ดังนั้นคุณจึงไม่เคยมี ssh shell / console มันสามารถเรียกใช้กระบวนการคอมไพล์ฝั่งเซิร์ฟเวอร์เท่านั้น
argent_smith

1
ดังนั้น scp จึงไม่ใช่ตัวเลือกสำหรับสถานการณ์นี้ถ้าสาขาหลักของคุณอยู่ใน gitub? มีข้อเสนอแนะอื่น ๆ ในการโอนที่ซ่อนในกรณีนั้นหรือ
Koen

1
ฉันพยายามเน้นว่าการโอนที่ซ่อนไม่สามารถทำได้เลย AFAIK
argent_smith มี. ค.

2

คำตอบที่ได้รับการยอมรับในขณะนี้เป็นเทคนิคที่ถูกต้องคุณไม่สามารถบอก Git ที่จะผลักดัน stashes ทั้งหมดของคุณไปไกลแล้วดึงทุกอย่างลงใน stashes ท้องถิ่นของคุณบนคอมพิวเตอร์เครื่องอื่น

และในขณะที่คำตอบขณะนี้บน upvotedควรทำงานผมไม่ชอบที่จะสร้างพวงของสาขาชั่วคราวและมันต้องใช้ด้วยตนเองการตรวจสอบจากที่ซ่อนกระทำและบันทึกเป็นที่ซ่อนซึ่งสามารถนำไปสู่ปัญหาเช่นความคิดเห็นนี้ กล่าวถึงOn (no branch): On testing:และนำไปสู่การซ้ำ แน่นอนต้องมีวิธีที่ดีกว่า!

ดังนั้นในขณะที่คุณไม่สามารถผลักดัน stashes, ซ่อนเป็นเพียงการกระทำ (ที่จริงทั้งสองกระทำ) และต่อgit pushหน้าคนคุณสามารถผลักดันกระทำ:

<src>มักจะเป็นชื่อของสาขาที่คุณต้องการที่จะผลักดัน แต่ก็สามารถใด ๆ โดยพล "SHA-1 การแสดงออก" ...

ฉันเลือกที่จะผลัก stashes refs/stashes/*เพื่อที่ฉันจะได้ไม่เกะกะระยะไกลด้วยกิ่งก้านพิเศษ ดังนั้นฉันสามารถทำได้ด้วย:

git push origin stash@{0}:refs/stashes/$(git rev-parse --short stash@{0})

( rev-parseคำสั่งได้รับแฮชแบบสั้นของที่เก็บซึ่งจะไม่ซ้ำกันสำหรับ repo)

ต่อไปฉันต้องดึงข้อมูลที่เก็บซ่อนจากคอมพิวเตอร์เครื่องอื่น Git ดึงเฉพาะสาขาตามค่าเริ่มต้นดังนั้นฉันจำเป็นต้องดึงข้อมูลที่เก็บเฉพาะ:

git fetch origin refs/stashes/*:refs/stashes/*

ทีนี้การแปลงที่เก็บข้อมูลกระทำกลับเป็นที่สะสมจริง ตามที่กล่าวไว้ในขณะที่ฉันสามารถตรวจสอบการกระทำที่ซ่อนรีเซ็ตและสะสมตามปกติฉันไม่ชอบที่ต้องใช้ขั้นตอนพิเศษหรือว่ามันอาจจะไม่รักษาสถานะดัชนีสำหรับที่เก็บ ฉันกำลังหาวิธีทำออนไลน์โดยอัตโนมัติ แต่การค้นหาของฉันล้มเหลว ในที่สุดฉันก็ตรวจดูหน้า man สำหรับgit stashที่ฉันพบสิ่งนี้:

สร้าง
สร้าง stash (ซึ่งเป็นวัตถุกระทำปกติ) และส่งคืนชื่อวัตถุโดยไม่เก็บไว้ที่ใดก็ได้ใน ref namespace สิ่งนี้มีวัตถุประสงค์เพื่อเป็นประโยชน์สำหรับสคริปต์ อาจไม่ใช่คำสั่งที่คุณต้องการใช้ ดู "บันทึก" ด้านบน

ร้านค้าจัด
เก็บสะสมที่กำหนดที่สร้างขึ้นผ่าน Git Stash สร้าง (ซึ่งเป็นความมุ่งมั่นผสานผสาน) ในการอ้างอิงสะสมการปรับปรุงการอ้างอิงที่เก็บสะสม สิ่งนี้มีวัตถุประสงค์เพื่อเป็นประโยชน์สำหรับสคริปต์ อาจไม่ใช่คำสั่งที่คุณต้องการใช้ ดู "บันทึก" ด้านบน

เนื่องจากฉันมีความมุ่งมั่นแล้วstoreเสียงเหมือนสิ่งที่ฉันต้องการ ดังนั้นฉันสามารถทำ:

git stash store --message "$(git show --no-patch --format=format:%s <SHA>)" <SHA>

แทนที่<SHA>ด้วยที่เก็บที่เพิ่งดึงมา

( git showคำสั่งจะได้รับข้อความการส่งข้อมูลจาก stash commit เพื่อใช้เป็นข้อความสำหรับ stash log)

ที่เก็บตอนนี้ปรากฏขึ้นตามปกติใน repo ท้องถิ่นของฉัน:

$ git stash list
stash@{0}: On master: temp
...

เพื่อล้างข้อมูลรีโมตสามารถลบ stashes ออกจากรีโมตได้ดังนี้:

git push origin :refs/stashes/<SHA>

วิธีนี้ยังมีประโยชน์ในการเป็น idempotent: ถ้าคุณเรียกใช้คำสั่งอีกครั้งก็จะรายงานpush คำสั่งนอกจากนี้ยังสามารถทำงานได้อย่างปลอดภัยซ้ำแล้วซ้ำอีก แม้ว่าจะข้ามการจัดเก็บที่เก็บหากเหมือนกันกับที่เก็บข้อมูลล่าสุด แต่ก็ไม่ได้ป้องกันการซ้ำซ้อนของที่เก็บที่เก่ากว่า สิ่งนี้สามารถแก้ไขได้ตามที่ฉันทำในสคริปต์ของฉันดูด้านล่างEverything up-to-datefetchstash storegit-rstash


สำหรับการทำให้สมบูรณ์คุณยังสามารถดันการหยุดทั้งหมด (ด้วย ):

for i in $(seq 0 $(expr $(git rev-list --walk-reflogs --count stash) - 1))
do
  git push origin stash@{$i}:refs/stashes/$(git rev-parse --short stash@{$i})
done

หรือนำเข้าที่เก็บข้อมูลที่ดึงมาทั้งหมด:

for stash in $(ls .git/refs/stashes)
do
  git stash store --message "$(git show --no-patch --format=format:%s $stash)" $stash
done

ฉันได้สร้าง สคริปต์ที่สามารถเรียกได้ว่าเป็นคำสั่งย่อย (เช่นgit rstash push 0) ดังนั้นฉันไม่จำเป็นต้องจำสิ่งเหล่านี้ทั้งหมด git-rstashสามารถพบได้ที่นี่


1

ต่อไปนี้ใช้ไม่ได้กับ stash แต่มีการเปลี่ยนแปลงที่ไม่มีข้อผูกมัดใน dir ที่ทำงาน มันสร้างสาขาโดยอัตโนมัติทำการเปลี่ยนแปลงปัจจุบันทั้งหมดและผลักดันไปยังระยะไกล:

commit_and_push_ ( ) {
    # This will:
    #  1. checkout a new branch stash-XXX
    #  2. commit the current changes in that branch
    #  3. push the branch to the remote
    local locbr=${1:-autostash-XXX}
    git checkout -b $locbr
    git add .
    git commit -a -m "Automatically created commit"
    git push origin $locbr
    echo "Autocommitted changes in branch $locbr ..."
}

ใช้เช่น:

commit_and_push_ my-temp-branch
commit_and_push_

0

ฉันเพียงแค่สร้างสาขาที่ซ่อนใหม่และลบเมื่อใดก็ตามที่ไม่จำเป็นต้องใช้สาขานั้น

git add . // Add work-in-progress job
git checkout -b stash-branch // Create and checkout to stash-branch
git commit -m 'WIP: job description' // Commit message
git push origin stash-branch // Push to remote
git pull origin stash-branch // Pull the stash-branch
git checkout master // Checkout to working branch
git rebase stash-branch // Rebase the stash-branch
git reset --soft // Equivalent to stash!!
git branch -d stash-branch // Delete when not needed from local
git push -d origin stash-branch // Delete when not needed from remote

-9

เพียงแค่ใช้ Dropbox เหมือนที่ผู้ชายคนนี้ทำ ด้วยวิธีนี้คุณไม่ต้องกังวลกับการกดหยุดเนื่องจากรหัสทั้งหมดของคุณจะถูกสำรอง

http://blog.sapegin.me/all/github-vs-dropbox


2
ก่อนที่ทุกคนจะมีปฏิกิริยากระตุกเข่าฉันไม่ได้บอกให้ใช้ Dropbox แทน Github แต่เพื่อเก็บรหัสที่ไม่พร้อมสำหรับการส่งใน Dropbox ซึ่งยังคงอยู่ภายใต้การควบคุมเวอร์ชัน
NYC Tech Engineer

4
มันจะใช้เวลามากเกินไปในการคัดลอกโครงการทั้งหมดไปยังคลาวด์ระยะไกล
Stav Alfi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.