ดูเหมือนว่ามีสองสถานการณ์ที่แตกต่างกันในการสนทนานี้:
สถานการณ์ที่ 1
การใช้พอยน์เตอร์ของที่เก็บพาเรนต์ของฉันไปยัง submodules ฉันต้องการตรวจสอบคอมมิทในแต่ละ submodule ที่ที่เก็บพาเรนต์ชี้ไปที่อาจเป็นไปได้หลังจากทำการวนซ้ำผ่าน submodules ทั้งหมดและอัปเดต / ดึงสิ่งเหล่านี้จากระยะไกล
นี่คือตามที่อธิบายไว้ทำด้วย
git submodule foreach git pull origin BRANCH
git submodule update
สถานการณ์ที่ 2 ซึ่งฉันคิดว่าเป็นสิ่งที่ OP เล็งไปที่
มีสิ่งใหม่เกิดขึ้นใน submodules หนึ่งรายการขึ้นไปและฉันต้องการ 1) ดึงการเปลี่ยนแปลงเหล่านี้และ 2) อัปเดตที่เก็บพาเรนต์เพื่อชี้ไปที่ HEAD (ล่าสุด) คอมมิทเหล่านี้
จะทำโดย
git submodule foreach git pull origin BRANCH
git add module_1_name
git add module_2_name
......
git add module_n_name
git push origin BRANCH
ไม่สามารถใช้งานได้จริงเนื่องจากคุณจะต้องฮาร์ดโค้ด n พา ธ ไปยัง n submodules ทั้งหมดเช่นสคริปต์เพื่ออัปเดตพอยน์เตอร์คอมมิชชันของที่เก็บพาเรนต์
จะเป็นการดีหากมีการวนซ้ำอัตโนมัติผ่านแต่ละ submodule อัปเดตตัวชี้พื้นที่เก็บข้อมูลหลัก (โดยใช้git add
) เพื่อชี้ไปที่ส่วนหัวของ submodule
สำหรับสิ่งนี้ฉันทำสคริปต์ Bash ขนาดเล็กนี้:
git-update-submodules.sh
#!/bin/bash
APP_PATH=$1
shift
if [ -z $APP_PATH ]; then
echo "Missing 1st argument: should be path to folder of a git repo";
exit 1;
fi
BRANCH=$1
shift
if [ -z $BRANCH ]; then
echo "Missing 2nd argument (branch name)";
exit 1;
fi
echo "Working in: $APP_PATH"
cd $APP_PATH
git checkout $BRANCH && git pull --ff origin $BRANCH
git submodule sync
git submodule init
git submodule update
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
git commit -m "Updated $BRANCH branch of deployment repo to point to latest head of submodules"
git push origin $BRANCH
หากต้องการเรียกใช้งานให้เรียกใช้งาน
git-update-submodules.sh /path/to/base/repo BRANCH_NAME
รายละเอียดเพิ่มเติม
ก่อนอื่นฉันคิดว่าสาขาที่มีชื่อ $ BRANCH (อาร์กิวเมนต์ที่สอง) มีอยู่ในที่เก็บทั้งหมด รู้สึกอิสระที่จะทำให้สิ่งนี้ซับซ้อนยิ่งขึ้น
คู่แรกของส่วนคือการตรวจสอบว่ามีข้อโต้แย้งบางอย่าง จากนั้นฉันก็ดึงสิ่งล่าสุดของพื้นที่เก็บข้อมูลของผู้ปกครอง (ฉันชอบที่จะใช้ --ff (การส่งต่ออย่างรวดเร็ว) เมื่อใดก็ตามที่ฉันเพิ่งจะดึงฉันมี rebase off, BTW)
git checkout $BRANCH && git pull --ff origin $BRANCH
ดังนั้นการเริ่มต้น submodule บางครั้งอาจมีความจำเป็นถ้ามีการเพิ่ม submodule ใหม่หรือยังไม่ได้เริ่มต้น:
git submodule sync
git submodule init
git submodule update
จากนั้นฉันจะอัปเดต / ดึงข้อมูลทั้งหมด:
git submodule foreach "(git checkout $BRANCH && git pull --ff origin $BRANCH && git push origin $BRANCH) || true"
สังเกตสิ่งเล็ก ๆ น้อย ๆ : อย่างแรกเลยฉันกำลังใช้คำสั่ง Git บางคำสั่ง&&
- หมายถึงคำสั่งก่อนหน้านี้จะต้องดำเนินการโดยไม่มีข้อผิดพลาด
หลังจากการดึงสำเร็จที่เป็นไปได้ (หากพบสิ่งใหม่ในระยะไกล) ฉันพยายามผลักดันเพื่อให้แน่ใจว่าการผสานการกระทำที่เป็นไปได้จะไม่ถูกทิ้งไว้บนไคลเอนต์ อีกครั้งมันจะเกิดขึ้นถ้ามีการดึงสิ่งใหม่เข้ามา
ในที่สุดสุดท้าย|| true
คือการตรวจสอบให้แน่ใจว่าสคริปต์ต่อข้อผิดพลาด ในการทำให้งานนี้ทุกอย่างในการวนซ้ำต้องถูกล้อมด้วยเครื่องหมายคำพูดคู่และคำสั่ง Git จะถูกรวมอยู่ในวงเล็บ (ลำดับความสำคัญของโอเปอเรเตอร์)
ส่วนที่ฉันชอบ:
for i in $(git submodule foreach --quiet 'echo $path')
do
echo "Adding $i to root repo"
git add "$i"
done
ทำซ้ำทั้งหมด submodules - ด้วย--quiet
ซึ่งจะเอาเอาท์พุท 'Entering MODULE_PATH' การใช้'echo $path'
(ต้องอยู่ในเครื่องหมายคำพูดเดี่ยว) พา ธ ไปยัง submodule จะถูกเขียนไปยังเอาต์พุต
รายการพา ธ ของ submodule แบบสัมพัทธ์นี้จะถูกจับในอาเรย์ ( $(...)
) - ในที่สุดวนซ้ำสิ่งนี้และทำgit add $i
เพื่ออัพเดตที่เก็บพาเรนต์
ในที่สุดการคอมมิทด้วยข้อความอธิบายว่าที่เก็บพาเรนต์ถูกอัพเดต การมอบหมายนี้จะถูกละเว้นโดยค่าเริ่มต้นหากไม่มีอะไรทำ กดปุ่มนี้เพื่อเริ่มต้นและคุณทำเสร็จแล้ว
ฉันมีสคริปต์ที่ใช้งานนี้ในงานJenkinsที่เชื่อมโยงกับการปรับใช้อัตโนมัติตามกำหนดเวลาหลังจากนั้นและทำงานได้อย่างมีเสน่ห์
ฉันหวังว่านี่จะเป็นประโยชน์กับใครบางคน
--remote
ตัวเลือกบางทีมันอาจจะมีประโยชน์ที่จะทำเครื่องหมายว่าเป็นคำตอบที่ยอมรับมากกว่าวิธีการ "ด้วยมือ" ในคำตอบของ Jason