ยกเลิกการ submodule git submodule


378

ฉันจะยกเลิกการส่ง submodule git submodule ได้อย่างไร (นำโค้ดทั้งหมดกลับสู่แกนกลาง)

เช่นเดียวกับวิธี "ควร" ฉันเช่นเดียวกับ "ขั้นตอนที่ดีที่สุด" ...


5
หมายเหตุ: ด้วย git1.8.3 ตอนนี้คุณสามารถลองgit submodule deinitดูคำตอบของฉันด้านล่าง
VonC

6
ฉันอาจเข้าใจผิด แต่ git submodule deinit ดูเหมือนว่าจะลบรหัส
Joe Germuska

2
ตั้งแต่ git 1.8.5 (พฤศจิกายน 2013) มีความง่ายgit submodule deinit asubmodule ; git rm asubmoduleพอดังแสดงในคำตอบของฉันด้านล่าง
VonC

พิจารณาใช้ทรีย่อย
HiB

คำตอบ:


527

หากสิ่งที่คุณต้องการคือการใส่รหัส submodule ของคุณลงในแหล่งเก็บข้อมูลหลักคุณเพียงแค่ลบ submodule และเพิ่มไฟล์เข้าไปใน repo หลักอีกครั้ง:

git rm --cached submodule_path # delete reference to submodule HEAD (no trailing slash)
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference
git commit -m "remove submodule"

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

ในโมดูลหลักคุณจะต้องทำสิ่งต่อไปนี้:

# Fetch the submodule commits into the main repository
git remote add submodule_origin git://url/to/submodule/origin
git fetch submodule_origin

# Start a fake merge (won't change any files, won't commit anything)
git merge -s ours --no-commit submodule_origin/master

# Do the same as in the first solution
git rm --cached submodule_path # delete reference to submodule HEAD
git rm .gitmodules             # if you have more than one submodules,
                               # you need to edit this file instead of deleting!
rm -rf submodule_path/.git     # make sure you have backup!!
git add submodule_path         # will add files instead of commit reference

# Commit and cleanup
git commit -m "removed submodule"
git remote rm submodule_origin

พื้นที่เก็บข้อมูลที่ได้จะมีลักษณะแปลก ๆ : จะมีการกระทำเริ่มต้นมากกว่าหนึ่ง แต่มันจะไม่ทำให้เกิดปัญหาใด ๆ สำหรับคอมไพล์

ในการแก้ปัญหาครั้งที่สองนี้คุณจะได้รับประโยชน์อย่างมากจากการที่คุณยังสามารถเรียกใช้ git blame หรือ git log ในไฟล์ที่อยู่ใน submodules ในความเป็นจริงสิ่งที่คุณทำที่นี่คือการเปลี่ยนชื่อไฟล์จำนวนมากภายในที่เก็บเดียวและ git ควรตรวจสอบเรื่องนี้โดยอัตโนมัติ หากคุณยังคงมีปัญหากับบันทึก git ลองใช้ตัวเลือก (--follow, -M, -C) ซึ่งจะทำการเปลี่ยนชื่อ / ตรวจจับสำเนาได้ดีขึ้น


3
ฉันคิดว่าฉันต้องทำวิธีที่สองของคุณ (เก็บประวัติ) ใน repos git บางอย่างที่ฉันมี คุณช่วยอธิบายได้ไหมว่าส่วนใดของคำสั่งด้านบนทำให้ไฟล์จาก submodule สิ้นสุดลงในไดเรกทอรีย่อย? มันคือคุณเมื่อคุณทำคอมไพล์ผสานนำไฟล์ในไดเรกทอรีระดับบนสุด (มีประวัติ) แต่เมื่อคุณทำคอมไพล์เพิ่ม submodule_path มัน implicity ไม่ git mv สำหรับทุกไฟล์?
Bowie Owens

5
โดยทั่วไปแล้วใช่ เคล็ดลับคือคอมไพล์ไม่ได้จัดเก็บการดำเนินการเปลี่ยนชื่อ: แต่จะตรวจจับพวกมันโดยดูจากการกระทำของผู้ปกครอง หากมีเนื้อหาไฟล์ที่มีอยู่ในการกระทำก่อนหน้านี้ แต่มีชื่อไฟล์ที่แตกต่างกันก็จะถือว่าการเปลี่ยนชื่อ (หรือคัดลอก) ในขั้นตอนข้างต้นgit mergeตรวจสอบให้แน่ใจว่าจะมี "การกระทำก่อนหน้า" สำหรับทุกไฟล์ (ที่หนึ่งในสอง "ด้าน" ของการผสาน)
gyim

6
ขอบคุณ gyim ฉันเริ่มโครงการที่ฉันคิดว่ามันสมเหตุสมผลที่จะแยกสิ่งต่าง ๆ ออกเป็นสองสามแหล่งเก็บข้อมูลและเชื่อมโยงมันกลับเข้าด้วยกันกับ submodules แต่ตอนนี้ดูเหมือนว่าผ่านการออกแบบและฉันต้องการรวมพวกเขากลับมารวมกันโดยไม่เสียประวัติของฉัน
Bowie Owens

4
@thuke ฉันมีปัญหานี้ด้วย มันสามารถแก้ไขได้โดยก่อนที่จะทำตามขั้นตอนเหล่านี้ย้ายไฟล์ทั้งหมดจากที่เก็บ submodules ของคุณลงในโครงสร้างไดเรกทอรีที่มีเส้นทางเดียวกันกับพื้นที่เก็บข้อมูลที่คุณกำลังจะรวม: เช่น ถ้า submodule ของคุณในที่เก็บหลักอยู่ใน foo / ใน submodule mkdir foo && git mv !(foo) foo && git commitดำเนิน
Chris Down

35
ต้องการเพิ่ม--allow-unrelated-historiesเพื่อบังคับให้ทำการผสานในขณะที่ฉันได้รับfatal: refusing to merge unrelated historiesข้อมูลเพิ่มเติมที่นี่: github.com/git/git/blob/master/Documentation/RelNotes/
......

72

ตั้งแต่git 1.8.5 (พฤศจิกายน 2013 ) ( โดยไม่เก็บประวัติของ submodule ):

mv yoursubmodule yoursubmodule_tmp
git submodule deinit yourSubmodule
git rm yourSubmodule
mv yoursubmodule_tmp yoursubmodule
git add yoursubmodule

นั่นจะ:

  • ยกเลิกการลงทะเบียนและยกเลิกการโหลด (เช่นลบเนื้อหาของ ) submodule ( deinitซึ่งเป็นmv ครั้งแรก )
  • ทำความสะอาด.gitmodulesเพื่อคุณ ( rm)
  • และลบรายการพิเศษที่เป็นตัวแทนของ submodule SHA1 ในดัชนีของ parent repo ( rm)

เมื่อการลบ submodule เสร็จสมบูรณ์ ( deinitและgit rm) คุณสามารถเปลี่ยนชื่อโฟลเดอร์กลับเป็นชื่อเดิมและเพิ่มไปยัง git repo เป็นโฟลเดอร์ปกติ

หมายเหตุ: หาก submodule ถูกสร้างขึ้นโดยเก่า Git (<1.8) คุณอาจต้องลบซ้อนกัน.gitโฟลเดอร์ภายใน submodule ตัวเองเป็นความเห็นโดยไซมอนตะวันออก


หากคุณจำเป็นต้องเก็บประวัติของ submodule ให้ดูjsears 's คำตอบgit filter-branchซึ่งการใช้งาน


5
สิ่งนี้จะลบออกจากแผนผังการทำงานใน 1.8.4 (ลบไดโอด submodule ทั้งหมดของฉัน)
Chris Down

@Chris คุณหมายถึงdeinitคนเดียวที่ทำความสะอาดต้นไม้ที่ทำงานจาก submodule ของคุณหรือไม่
VonC

ใช่มันจะลบเนื้อหาทั้งหมดในไดเรกทอรี submodule
Chris Down

2
@mschuett ไม่คุณไม่ได้หายไปอะไร: submodule ไม่มี. git ในนั้นในตอนแรก หากเป็นกรณีสำหรับคุณมันเป็น repo ที่ซ้อนกันไม่ใช่ submodule นั่นอธิบายว่าทำไมคำตอบข้างต้นจะไม่นำมาใช้ในกรณีของคุณ สำหรับความแตกต่างระหว่างทั้งสองดูstackoverflow.com/a/34410102/6309
VonC

1
@VonC ตอนนี้ฉันอยู่ที่ 2.9.0.windows.1 อย่างไรก็ตาม submodules อาจถูกสร้างขึ้นเมื่อหลายปีก่อนในคอมไพล์รุ่นก่อนหน้านี้ฉันไม่แน่ใจ ฉันคิดว่าขั้นตอนดูเหมือนจะใช้ได้ตราบใดที่ฉันลบไฟล์นั้นออกก่อนที่จะเพิ่ม + คอมมิชชันขั้นสุดท้าย
Simon East

67

ฉันได้สร้างสคริปต์ที่จะแปล submodule เป็นไดเรกทอรีอย่างง่ายในขณะที่เก็บประวัติไฟล์ทั้งหมด ไม่ประสบgit log --follow <file>ปัญหาที่โซลูชันอื่นประสบ นอกจากนี้ยังเป็นคำขอร้องแบบบรรทัดเดียวที่ใช้งานได้ง่ายสำหรับคุณ G'luck

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

รหัสล่าสุดจะได้รับการปรับปรุงด้วยการแก้ไขข้อผิดพลาดใน github ที่https://github.com/jeremysears/scripts/blob/master/bin/git-submodule-rewriteแต่เพื่อประโยชน์ของคำตอบที่เหมาะสม การแก้ปัญหาอย่างครบถ้วนด้านล่าง

การใช้งาน:

$ git-submodule-rewrite <submodule-name>

-git submodule-เขียน:

#!/usr/bin/env bash

# This script builds on the excellent work by Lucas Jenß, described in his blog
# post "Integrating a submodule into the parent repository", but automates the
# entire process and cleans up a few other corner cases.
# https://x3ro.de/2013/09/01/Integrating-a-submodule-into-the-parent-repository.html

function usage(){
  echo "Merge a submodule into a repo, retaining file history."
  echo "Usage: $0 <submodule-name>"
  echo ""
  echo "options:"
  echo "  -h, --help                Print this message"
  echo "  -v, --verbose             Display verbose output"
}

function abort {
    echo "$(tput setaf 1)$1$(tput sgr0)"
    exit 1
}

function request_confirmation {
    read -p "$(tput setaf 4)$1 (y/n) $(tput sgr0)"
    [ "$REPLY" == "y" ] || abort "Aborted!"
}

function warn() {
  cat << EOF
    This script will convert your "${sub}" git submodule into
    a simple subdirectory in the parent repository while retaining all
    contents and file history.

    The script will:
      * delete the ${sub} submodule configuration from .gitmodules and
        .git/config and commit it.
      * rewrite the entire history of the ${sub} submodule so that all
        paths are prefixed by ${path}.
        This ensures that git log will correctly follow the original file
        history.
      * merge the submodule into its parent repository and commit it.

    NOTE: This script might completely garble your repository, so PLEASE apply
    this only to a fresh clone of the repository where it does not matter if
    the repo is destroyed.  It would be wise to keep a backup clone of your
    repository, so that you can reconstitute it if need be.  You have been
    warned.  Use at your own risk.

EOF

  request_confirmation "Do you want to proceed?"
}

function git_version_lte() {
  OP_VERSION=$(printf "%03d%03d%03d%03d" $(echo "$1" | tr '.' '\n' | head -n 4))
  GIT_VERSION=$(git version)
  GIT_VERSION=$(printf "%03d%03d%03d%03d" $(echo "${GIT_VERSION#git version}" | tr '.' '\n' | head -n 4))
  echo -e "${GIT_VERSION}\n${OP_VERSION}" | sort | head -n1
  [ ${OP_VERSION} -le ${GIT_VERSION} ]
}

function main() {

  warn

  if [ "${verbose}" == "true" ]; then
    set -x
  fi

  # Remove submodule and commit
  git config -f .gitmodules --remove-section "submodule.${sub}"
  if git config -f .git/config --get "submodule.${sub}.url"; then
    git config -f .git/config --remove-section "submodule.${sub}"
  fi
  rm -rf "${path}"
  git add -A .
  git commit -m "Remove submodule ${sub}"
  rm -rf ".git/modules/${sub}"

  # Rewrite submodule history
  local tmpdir="$(mktemp -d -t submodule-rewrite-XXXXXX)"
  git clone "${url}" "${tmpdir}"
  pushd "${tmpdir}"
  local tab="$(printf '\t')"
  local filter="git ls-files -s | sed \"s/${tab}/${tab}${path}\//\" | GIT_INDEX_FILE=\${GIT_INDEX_FILE}.new git update-index --index-info && mv \${GIT_INDEX_FILE}.new \${GIT_INDEX_FILE}"
  git filter-branch --index-filter "${filter}" HEAD
  popd

  # Merge in rewritten submodule history
  git remote add "${sub}" "${tmpdir}"
  git fetch "${sub}"

  if git_version_lte 2.8.4
  then
    # Previous to git 2.9.0 the parameter would yield an error
    ALLOW_UNRELATED_HISTORIES=""
  else
    # From git 2.9.0 this parameter is required
    ALLOW_UNRELATED_HISTORIES="--allow-unrelated-histories"
  fi

  git merge -s ours --no-commit ${ALLOW_UNRELATED_HISTORIES} "${sub}/master"
  rm -rf tmpdir

  # Add submodule content
  git clone "${url}" "${path}"
  rm -rf "${path}/.git"
  git add "${path}"
  git commit -m "Merge submodule contents for ${sub}"
  git config -f .git/config --remove-section "remote.${sub}"

  set +x
  echo "$(tput setaf 2)Submodule merge complete. Push changes after review.$(tput sgr0)"
}

set -euo pipefail

declare verbose=false
while [ $# -gt 0 ]; do
    case "$1" in
        (-h|--help)
            usage
            exit 0
            ;;
        (-v|--verbose)
            verbose=true
            ;;
        (*)
            break
            ;;
    esac
    shift
done

declare sub="${1:-}"

if [ -z "${sub}" ]; then
  >&2 echo "Error: No submodule specified"
  usage
  exit 1
fi

shift

if [ -n "${1:-}" ]; then
  >&2 echo "Error: Unknown option: ${1:-}"
  usage
  exit 1
fi

if ! [ -d ".git" ]; then
  >&2 echo "Error: No git repository found.  Must be run from the root of a git repository"
  usage
  exit 1
fi

declare path="$(git config -f .gitmodules --get "submodule.${sub}.path")"
declare url="$(git config -f .gitmodules --get "submodule.${sub}.url")"

if [ -z "${path}" ]; then
  >&2 echo "Error: Submodule not found: ${sub}"
  usage
  exit 1
fi

if ! [ -d "${path}" ]; then
  >&2 echo "Error: Submodule path not found: ${path}"
  usage
  exit 1
fi

main

ไม่ทำงานบน Ubuntu 16.04 ฉันส่งคำขอการดึงไปยัง repo Github
qznc

1
เยี่ยมมาก @qznc สิ่งนี้ได้รับการทดสอบบน OSX ฉันจะผสานอย่างมีความสุขเมื่อมันผ่านทั้งสองแพลตฟอร์ม
jsears

@qznc Ubuntu 16.04 รองรับการผสานและตอบรับการปรับปรุง
jsears

2
นี่คือคำตอบที่ดีที่สุดรักษาประวัติศาสตร์ทั้งหมด ดีมาก!
CharlesB

1
ทำงานทั้งหมดโดยไม่มีข้อผิดพลาดใน Git Bash 2.20.1.1 บน Windows 10 ด้วยรุ่นล่าสุดจาก github: curl https://raw.githubusercontent.com/jeremysears/scripts/master/bin/git-submodule-rewrite > git-submodule-rewrite.shและ./git-submodule-rewrite.sh <submodule-name>
Alexey

32
  1. git rm --cached the_submodule_path
  2. ลบส่วน submodule จาก.gitmodulesไฟล์หรือถ้าเป็น submodule เพียงไฟล์เดียวให้ลบไฟล์
  3. ทำกระทำ "ลบ submodule xyz"
  4. git add the_submodule_path
  5. อื่นกระทำ "เพิ่ม codebase ของ xyz"

ฉันยังไม่พบวิธีที่ง่ายขึ้นเลย คุณสามารถบีบอัด 3-5 เป็นขั้นตอนเดียวผ่านgit commit -a- เรื่องของรสนิยม


6
ไม่ควรที่จะเป็น.gitmodulesแทน.submodules?
imz - Ivan Zakharyaschev

1
มันควรจะเป็น.gitmodulesไม่ได้.submodules
Mkey

1
ฉันต้องลบ.gitไดเรกทอรีของ submodule ก่อนที่git addจะสามารถทำงานกับโฟลเดอร์ submodule ได้
Carson Evans

16

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

ตัวอย่างเช่นนี้ repo หลักจะgit@site.com:main/main.gitและ repo submodule git@site.com:main/child.gitจะ สมมติว่า submodule ตั้งอยู่ในไดเรกทอรีรากของ repo หลัก ปรับคำแนะนำตามต้องการ

เริ่มต้นด้วยการโคลน repo ผู้ปกครองและลบ submodule เก่า

git clone git@site.com:main/main.git
git submodule deinit child
git rm child
git add --all
git commit -m "remove child submodule"

ตอนนี้เราจะเพิ่ม repos ลูกทุ่งขึ้นเหนือ repo หลัก

git remote add upstream git@site.com:main/child.git
git fetch upstream
git checkout -b merge-prep upstream/master

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

mkdir child

ย้ายโฟลเดอร์และไฟล์ทั้งหมดยกเว้นโฟลเดอร์. git ไปยังโฟลเดอร์ย่อย

git add --all
git commit -m "merge prep"

ตอนนี้คุณสามารถรวมไฟล์ของคุณกลับเข้าไปในสาขาหลัก

git checkout master
git merge merge-prep # --allow-unrelated-histories merge-prep flag may be required 

มองไปรอบ ๆ และตรวจสอบให้แน่ใจว่าทุกอย่างดูดีก่อนใช้ git push

สิ่งหนึ่งที่คุณต้องจำไว้ตอนนี้คือบันทึก git ไม่ได้ตามค่าเริ่มต้นตามไฟล์ที่ถูกย้าย แต่ด้วยการรันgit log --follow filenameคุณสามารถดูประวัติเต็มของไฟล์ของคุณได้


2
ผมได้ไปตลอดทางจนถึงสุดท้ายและได้รับข้อผิดพลาดgit merge merge-prep การแก้ปัญหานี้คือ:fatal: refusing to merge unrelated histories git merge --allow-unrelated-histories merge-prep
Humblehacker

@ humblehacker ขอบคุณฉันได้เพิ่มความคิดเห็นเล็กน้อยในกรณีที่คนอื่นทำงานในนี้เช่นกัน
mschuett

1
คำตอบที่ดีที่สุดในการเก็บประวัติของ submodule ขอบคุณ @mschuett
Anton Temchenko

ในตัวอย่างที่นี่มีวิธีใดที่จะดึงไฟล์ของอัปสตรีมลงในchildไดเรกทอรีดังนั้นคุณไม่ต้องย้ายไฟล์เหล่านั้นในภายหลัง ฉันมีชื่อไฟล์เหมือนกันใน submodule และ repo หลัก ... ดังนั้นฉันจึงได้รับความขัดแย้งในการรวมเนื่องจากมันพยายามรวมสองไฟล์เข้าด้วยกัน
Skitterm

อาจเป็นไปได้ แต่ฉันก็ไม่รู้เหมือนกัน ฉันเป็นการส่วนตัวที่จะทำการส่งไฟล์ใน repo ที่คุณพยายามจะย้ายเข้าไปอยู่ในได
เร็กตอรี่ที่

12

มันเกิดขึ้นกับเราว่าเราได้สร้างที่เก็บ 2 แห่งสำหรับ 2 โครงการที่มีการเชื่อมโยงกันมากจนไม่มีความรู้สึกใดที่จะแยกพวกเขาออกจากกันดังนั้นเราจึงรวมมันเข้าด้วยกัน

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

หากคุณใช้งาน submodule และคุณต้องการที่จะแปลงมันเป็นไดเรกทอรีที่คุณสามารถทำได้:

git clone project_uri project_name

ที่นี่เราทำการโคลนที่สะอาดเพื่อทำงาน สำหรับกระบวนการนี้คุณไม่จำเป็นต้องเริ่มต้นหรืออัปเดต submodules ดังนั้นเพียงข้ามไป

cd project_name
vim .gitmodules

แก้ไข.gitmodulesด้วยโปรแกรมแก้ไขที่คุณชื่นชอบ (หรือ Vim) เพื่อลบ submodule ที่คุณต้องการแทนที่ บรรทัดที่คุณต้องการลบควรมีลักษณะดังนี้:

[submodule "lib/asi-http-request"]
    path = lib/asi-http-request
    url = https://github.com/pokeb/asi-http-request.git

หลังจากบันทึกไฟล์

git rm --cached directory_of_submodule
git commit -am "Removed submodule_name as submodule"
rm -rf directory_of_submodule

ที่นี่เราลบความสัมพันธ์ submodule อย่างสมบูรณ์เพื่อให้เราสามารถสร้างนำ repo อื่น ๆ ให้กับโครงการในสถานที่

git remote add -f submodule_origin submodule_uri
git fetch submodel_origin/master

ที่นี่เราเรียกที่เก็บ submodule เพื่อรวม

git merge -s ours --no-commit submodule_origin/master

ที่นี่เราเริ่มทำการผสานของที่เก็บ 2 แห่ง แต่หยุดก่อนที่จะคอมมิท

git read-tree --prefix=directory_of_submodule/ -u submodule_origin/master

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

git commit -am "submodule_name is now part of main project"

ที่นี่เราดำเนินการตามขั้นตอนให้เสร็จสิ้นเพื่อทำการเปลี่ยนแปลงในการผสาน

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


ดูเหมือนจะไม่ได้เก็บประวัติของไฟล์ submodule ไว้ฉันเพิ่งเห็นคอมมิทเดียวในบันทึก git สำหรับไฟล์ที่ถูกเพิ่มเข้าไปdirectory_of_submodule
Anentropic

@Anentropic ขออภัยที่รอการตอบกลับล่าช้า ฉันเพิ่งทำตามขั้นตอนเต็มรูปแบบอีกครั้ง (มีการแก้ไขเล็กน้อย) ขั้นตอนการเก็บประวัติทั้งหมด แต่ก็มีจุดผสานบางทีนั่นอาจเป็นเหตุผลว่าทำไมคุณไม่พบมัน หากคุณต้องการดูประวัติ submodule เพียงแค่ทำ "บันทึก git" ค้นหาการรวมกระทำ (ในตัวอย่างคือหนึ่งที่มีข้อความ "submodule_name เป็นส่วนหนึ่งของโครงการหลัก") มันจะมีผู้ปกครอง 2 คอมมิชชัน (Merge: sdasda asdasd), คอมไพล์บันทึกการคอมมิทครั้งที่สองและคุณได้รับ submodule / master history ทั้งหมดที่นั่น
dvicino

หน่วยความจำของฉันมัวตอนนี้ แต่ฉันคิดว่าฉันสามารถรับประวัติของไฟล์ submodule ที่ผสานได้โดยทำgit log original_path_of_file_in_submoduleเช่นเส้นทางที่ลงทะเบียนใน git repo สำหรับไฟล์ (ซึ่งไม่มีอยู่ในระบบไฟล์) อีกต่อไปแม้ว่าไฟล์ submodule ตอนนี้อาศัยอยู่ที่submodule_path/new_path_of_file
Anentropic

สิ่งนี้ไม่ได้เก็บรักษาประวัติศาสตร์ไว้อย่างดีและเส้นทางยังผิด ฉันรู้สึกว่าจำเป็นต้องใช้ตัวกรองแบบต้นไม้ แต่ฉันไม่สามารถทำอะไรได้ ... ลองสิ่งที่ฉันพบที่นี่: x3ro.de/2013/09/01/…
ลุค H

คำตอบนี้ล้าสมัยstackoverflow.com/a/16162228/11343 (VonC คำตอบ) ไม่เหมือนกัน แต่ดีกว่า
CharlesB


6

ต่อไปนี้เป็นคำตอบของ @ gyim รุ่นปรับปรุงเล็กน้อย (IMHO) เขากำลังทำการเปลี่ยนแปลงที่เป็นอันตรายในสำเนาการทำงานหลักซึ่งฉันคิดว่ามันง่ายกว่าที่จะใช้งานโคลนแบบแยกต่างหากจากนั้นจึงรวมเข้าด้วยกันในตอนท้าย

ในไดเรกทอรีที่แยกต่างหาก (เพื่อให้ทำผิดพลาดง่ายขึ้นในการทำความสะอาดและลองอีกครั้ง) ตรวจสอบทั้ง repo ด้านบนและ subrepo

git clone ../main_repo main.tmp
git clone ../main_repo/sub_repo sub.tmp

ขั้นแรกให้แก้ไขไฟล์ย่อยเพื่อย้ายไฟล์ทั้งหมดไปยังไดเรกทอรีย่อยที่ต้องการ

cd sub.tmp
mkdir sub_repo_path
git mv `ls | grep -v sub_repo_path` sub_repo_path/
git commit -m "Moved entire subrepo into sub_repo_path"

จดบันทึก HEAD

SUBREPO_HEAD=`git reflog | awk '{ print $1; exit; }'`

ตอนนี้ลบ subrepo ออกจาก repo หลัก

cd ../main.tmp
rmdir sub_repo_path
vi .gitmodules  # remove config for submodule
git add -A
git commit -m "Removed submodule sub_repo_path in preparation for merge"

และในที่สุดก็เพียงแค่ผสานพวกเขา

git fetch ../sub.tmp
# remove --allow-unrelated-histories if using git older than 2.9.0
git merge --allow-unrelated-histories $SUBREPO_HEAD

และทำ! อย่างปลอดภัยและไม่มีเวทมนตร์ใด ๆ


... คำตอบคืออะไร อาจต้องการอ้างอิงชื่อผู้ใช้และคำตอบยอดนิยมสามารถเปลี่ยนแปลงได้ตลอดเวลา
Contango

@Contango คำตอบอัพเดทแล้ว แต่คำตอบยอดนิยมยังคงเป็นคำตอบที่ดีที่สุดโดยมีคะแนนนำ 400 ;-)
dataless

สิ่งนี้ใช้งานได้หรือไม่หากไฟล์ย่อยนั้นมีไดเรกทอรีที่subrepoมีชื่ออยู่ในรายการอยู่แล้ว
detly

ในขั้นตอนสุดท้ายฉันได้รับข้อผิดพลาดต่อไปนี้: git merge $SUBREPO_HEAD fatal: refusing to merge unrelated historiesฉันควรใช้git merge $SUBREPO_HEAD --allow-unrelated-historiesในกรณีนี้หรือไม่ หรือควรจะทำงานโดยไม่ได้และฉันทำผิดพลาด?
Ti-

1
@ Ti-m ใช่นี่เป็นกรณีของการรวมสองประวัติที่ไม่ได้แชร์คอมมิชชันใด ๆ การป้องกันประวัติศาสตร์ที่ไม่เกี่ยวข้องดูเหมือนจะเป็นเรื่องใหม่ในคอมไพล์ตั้งแต่ฉันเขียนสิ่งนี้เป็นครั้งแรก; ฉันจะอัปเดตคำตอบของฉัน
dataless

3

สำหรับเมื่อไหร่

git rm [-r] --cached submodule_path

ผลตอบแทน

fatal: pathspec 'emr/normalizers/' did not match any files

บริบท: ฉันทำrm -r .git*ในโฟลเดอร์ submodule ของฉันก่อนที่จะทราบว่าพวกเขาจำเป็นต้องถูกยกเลิกการส่งข้อมูลในโครงการหลักที่ฉันเพิ่งเพิ่มเข้าไป ฉันได้รับข้อผิดพลาดด้านบนเมื่อยกเลิกการส่งข้อมูลบางส่วน แต่ไม่ใช่ทั้งหมด อย่างไรก็ตามฉันแก้ไขพวกเขาด้วยการวิ่ง (หลังแน่นอนrm -r .git*)

mv submodule_path submodule_path.temp
git add -A .
git commit -m "De-submodulization phase 1/2"
mv submodule_path.temp submodule_path
git add -A .
git commit -m "De-submodulization phase 2/2"

โปรดทราบว่านี่จะไม่เก็บประวัติ


3

จากคำตอบของ VonCฉันได้สร้างสคริปต์ทุบตีง่ายๆที่ทำสิ่งนี้ addในตอนท้ายมีการใช้สัญลักษณ์แทนมิฉะนั้นจะยกเลิกก่อนหน้านี้rmสำหรับ submodule ตัวเอง สิ่งสำคัญคือการเพิ่มเนื้อหาของไดเรกทอรี submodule และไม่ตั้งชื่อไดเรกทอรีเองในaddคำสั่ง

ในไฟล์ชื่อgit-integrate-submodule:

#!/usr/bin/env bash
mv "$1" "${1}_"
git submodule deinit "$1"
git rm "$1"
mv "${1}_" "$1"
git add "$1/**"

0

ฉันพบว่าสะดวกกว่าที่จะดึงข้อมูลการส่งข้อมูลภายในจาก submodule ด้วย (ไม่สามารถผลักดันพวกเขาเนื่องจากฉันไม่สามารถเข้าถึงรีโมตนั้นได้) ดังนั้นฉันจึงเพิ่ม submodule / .git เป็น remote_origin2 ดึงข้อมูลมาคอมมิชชันและผสานจากสาขานั้น ไม่แน่ใจว่าฉันยังต้องการ submodule remote เป็นแหล่งกำเนิดหรือไม่เนื่องจากฉันยังไม่คุ้นเคยกับคอมไพล์มากพอ


0

นี่คือสิ่งที่ฉันพบว่าดีที่สุดและง่ายที่สุด

ใน submodule repo จาก HEAD คุณต้องการรวมเป็น repo หลัก:

  • git checkout -b "mergeMe"
  • mkdir "foo/bar/myLib/" (พา ธ เหมือนกันกับตำแหน่งที่คุณต้องการไฟล์ใน repo หลัก)
  • git mv * "foo/bar/myLib/" (ย้ายไปยังเส้นทางทั้งหมด)
  • git commit -m "ready to merge into main"

กลับไปที่ repo หลักหลังจากลบ submodule และเคลียร์พา ธ "foo / bar / myLib":

  • git merge --allow-unrelated-histories SubmoduleOriginRemote/mergeMe

บูมเสร็จแล้ว

รักษาประวัติ

ไม่ต้องห่วง


โปรดทราบว่าคำตอบอื่น ๆ เกือบจะเหมือนกัน แต่นี่ถือว่าคุณเป็นเจ้าของ repododule นอกจากนี้ยังช่วยให้สามารถรับการเปลี่ยนแปลงต้นน้ำในอนาคตสำหรับ submodule

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