2011-03-24 162 views
2

我發現Using Git, what's the best way to subtree merge an external project that has submodules?但雖然相關,它不回答我的問題。Git命令自動子樹合併項目與子模塊?

假設我有我的父項目和我的子項目,它包含子模塊。如何將子項目子樹合併到父項目的子目錄中並保持對子模塊的引用工作?

我已經試過了諸如:

git remote add -f child_remote git://github.com/me/child.git 
git checkout -b child_branch child_remote/master 
git submodule init 
git submodule update 
git checkout master 
git read-tree --prefix=child_directory/ -u child_branch 

但讀樹失去的子模塊,並.gitmodules只出現在子目錄中。當我嘗試執行git子模塊init和git子模塊更新時,出現如下錯誤:「路徑'child_directory/submodule_directory'中找不到在.gitmodules中找到的子模塊映射」。

我也試着修改http://help.github.com/subtree-merge/上的說明以使用子模塊,但無濟於事。

我知道我可以通過手動修改.gitmodules文件來引用正確的路徑,或者在沒有子模塊的情況下合併Child項目,然後將它們重新添加到Parent項目中,但我認爲這兩者解決方案是黑客。我正在尋找人們會運行的實際命令來自動運行,而無需手動編輯任何內容。

+0

子樹合併的使用幾乎讓你越界「自動執行」。只需編輯路徑。 – 2011-03-25 06:13:46

回答

0

您可以更改.gitmodules中的路徑,然後執行git submodule init && git submodule update,也可以將子模塊轉換爲子樹。最後一個選項涉及某種腳本,因爲沒有自動執行此操作的方法。

當使用shell腳本,你可以使用這些函數來獲得子模塊和他們的名字(從混帳子模塊源):

# This lists the unmerged submodules 
module_list() 
{ 
    git ls-files --error-unmatch --stage -- "[email protected]" | 
    perl -e ' 
    my %unmerged =(); 
    my ($null_sha1) = ("0" x 40); 
    while (<STDIN>) { 
     chomp; 
     my ($mode, $sha1, $stage, $path) = 
      /^([0-7]+) ([0-9a-f]{40}) ([0-3])\t(.*)$/; 
     next unless $mode eq "160000"; 
     if ($stage ne "0") { 
      if (!$unmerged{$path}++) { 
       print "$mode $null_sha1 U\t$path\n"; 
      } 
      next; 
     } 
     print "$_\n"; 
    } 
    ' 
} 

# This gets the submodule's name from the .gitignore file in your webroot 
module_name() 
{ 
    # Do we have "submodule.<something>.path = $1" defined in .gitmodules file? 
    re=$(printf '%s\n' "$1" | sed -e 's/[].[^$\\*]/\\&/g') 
    name=$(git config -f $2/.gitmodules --get-regexp '^submodule\..*\.path$' | 
     sed -n -e 's|^submodule\.\(.*\)\.path '"$re"'$|\1|p') 
    test -z "$name" && 
    die "$(eval_gettext "No submodule mapping found in .gitmodules for path '\$path'")" 
    echo "$name" 
} 

然後,當你重複的結果,可以提取名稱和url用於子樹。

module_list | while read mode sha1 stage path 
do 
    #the path as your repo sees it 
    full_path=$path 

    #The path as .gitmodules in your child_directory sees it 
    fake_path=${path[*]/[child_directory]\//} 

    #Get the name of the submodule 
    stupid_name=$(module_name "$fake_path" "[child_directory]") 

    #Get the git URL from the .gitmodules file 
    git_url=$(git config -f [child_directory]/.gitmodules submodule."$stupid_name".url) 

    #Gets the clean name to use as remote name 
    new_remote=$(echo $git_url | cut -d. -f2 | cut -d/ -f2- | cut -d/ -f2) 

    #Remove the submodules folder 
    rm -rf $path 

    #Add the subtree 
    git remote add -f $new_remote $git_url 
    git merge -s ours --no-commit $new_remote/master 
    git read-tree --prefix=$full_path/ -u $new_remote/master 
    git commit -m "$new_remote merged in $full_path" 
done 

我敢肯定有一個更好的方式這樣做的方式,但它給人的是什麼做

0

爲什麼不能在項目中使用子模塊的想法?您現在可以全面使用'git submodule update --recursive`。

此外還有git-slave可以幫助您跨子模塊自動化分支。