Git - 子模块HEAD在运行更新后总是分离?

时间:2016-12-22 08:51:10

标签: git git-submodules git-detached-head

我在.gitmodules文件中有子模块的配置:

[submodule "sub"]
    shallow = true
    branch = master
    path = sub
    url = https://path/to/repo.git

现在我想要有人克隆我的仓库然后运行这些命令:

git submodule init
git submodule update

是获得子模块的浅层主分支。但是发生的事情是它没有签到master分支。它总是会分离头,所以我需要手动运行git checkout master。因此,用户只需运行一个命令,而不仅仅是这两个命令。

我调查了这个:Why is my GIT Submodule HEAD detached from master?

但任何关于已接受答案的建议似乎都没有帮助:我在.gitmodules文件中添加了我想要的分支,我添加了远程上游作为master(这仅适用于已经克隆/更新的存储库后)不得不结账以掌握自己)。

如果有人克隆了我的存储库并且想要设置子模块,那么这是否总是会分离HEAD?

2 个答案:

答案 0 :(得分:1)

是的,您是对的。用户mkungla从Why is my GIT Submodule HEAD detached from master?做出的最高答案是胡说八道。

branch中添加 .gitmodule选项 与子模块的分离行为完全无关

git submodule --help中,默认行为是git submodule update --remote 断开。

首先,无需指定要跟踪的分支origin/master是要跟踪的默认分支。

  

-远程

     

代替使用超级项目的记录的SHA-1更新子模块,而要使用子模块的远程跟踪分支的状态。使用的遥控器是分支机构的遥控器(branch.<name>.remote),默认为origin 。远程分支使用的默认值为master

为什么

那为什么在update之后分离HEAD?因为submodule.$name.update默认行为是checkout

  

-结帐

     

在子模块中的分离的HEAD 上签出超级项目中记录的提交。这是默认行为,此选项的主要用途是在设置为submodule.$name.update以外的值时覆盖checkout

如何

如果您希望子模块自动与远程分支合并,请使用--merge--rebase

  

-合并

     

此选项仅对更新命令有效。将超级项目中记录的提交合并到子模块的当前分支中。如果指定了此选项,则子模块的HEAD将不分离

     

-重新设置

     

将当前分支重新基于超级项目中记录的提交。如果指定了此选项,则子模块的HEAD将不分离

您需要做的就是

git submodule update --remote --merge
# or
git submodule update --remote --rebase

通过将--merge设置为--rebasegit submodule update,还可以选择将submodule.$name.updatemerge设置为rebase的默认行为

这是一个有关如何在.gitmodule中配置子模块更新的默认更新行为的示例。

[submodule "bash/plugins/dircolors-solarized"]
    path = bash/plugins/dircolors-solarized
    url = https://github.com/seebi/dircolors-solarized.git
    update = merge # <-- this is what you need to add

我的全部答案都基于手册。 git submodule --help

答案 1 :(得分:0)

我还在调查这个问题,但这是我提出并正在使用的脚本:

#! /bin/bash                                                                                                                                                                                 
# Written by Carlo Wood 2016                                                                                                                                                                 

echo "In \"$(pwd)\", entering $0 $*"                                                                                                                                                         

# This script should be run from the root of the parent project.                                                                                                                             
if ! test -e .git; then                                                                                                                                                                      
  echo "$0: $(pwd) is not a git repository."                                                                                                                                                 
  exit 1                                                                                                                                                                                     
fi                                                                                                                                                                                           

# Parse command line parameters.                                                                                                                                                             
opt_init=                                                                                                                                                                                    
opt_recursive=                                                                                                                                                                               
do_foreach=0                                                                                                                                                                                 
initial_call=1                                                                                                                                                                               
while [[ $# -gt 0 ]]                                                                                                                                                                         
do                                                                                                                                                                                           
  case $1 in                                                                                                                                                                                 
    --init)                                                                                                                                                                                  
      opt_init=$1                                                                                                                                                                            
      ;;                                                                                                                                                                                     
    --recursive)                                                                                                                                                                             
      opt_recursive=$1                                                                                                                                                                       
      do_foreach=1                                                                                                                                                                           
      ;;                                                                                                                                                                                     
    --reentry)
      initial_call=0
      ;;
    --)
      break;
      ;;
    -*)
      echo "Unknown option $1"
      exit 1
      ;;
    *)
      break
      ;;
  esac
  shift
done

# Determine the full path to this script.
if [[ ${0:0:1} = / ]]; then
  FULL_PATH="$0"
else
  FULL_PATH="$(realpath $0)"
fi

if test "$initial_call" -eq 1; then
  do_foreach=1
else
  # Script is called from git submodule foreach ...'
  name="$1"
  path="$2"
  sha1="$3"
  toplevel="$4"
  # Make sure we are in the right directory.
  cd "$toplevel/$path" || exit 1
  # Does the parent project want us to checkout a branch for this module?
  SUBMODULE_BRANCH=$(git config -f "$toplevel/.gitmodules" submodule.$name.branch)
  if test -n "$SUBMODULE_BRANCH"; then
    echo "Calling 'git checkout $SUBMODULE_BRANCH' in $(pwd)"
    git checkout $SUBMODULE_BRANCH || exit 1
    echo "Calling 'git pull' in $(pwd)"
    git pull || exit 1
    if test $(git rev-parse HEAD) != "$sha1"; then
      # Update the parent project to point to the head of this branch.
      pushd "$toplevel" >/dev/null
      SN1=$(git stash list | grep '^stash' | wc --lines)
      git stash save --quiet Automatic stash of parent project by update_submodules.sh
      SN2=$(git stash list | grep '^stash' | wc --lines)
      git add $name
      git commit -m "Update of submodule $name to current $SUBMODULE_BRANCH"
      if test $SN1 -ne $SN2; then
        git stash pop --quiet
      fi
      popd >/dev/null
    fi
  elif test $(git rev-parse HEAD) != "$sha1"; then
    # No submodule.$name.branch for this submodule. Just checkout the detached HEAD.
    git checkout $sha1
  fi
fi

echo "do_foreach=$do_foreach; opt_init=$opt_init; opt_recursive=$opt_recursive; name=$name; path=$path; sha1=$sha1; toplevel=$toplevel; pwd=$(pwd)"

if test $do_foreach -eq 1; then
  if test -n "$opt_init"; then
    echo "Calling 'git submodule init'"
    git submodule init
  fi
  # Make sure the submodules even exist.
  echo "Calling 'git submodule update'"
  git submodule update
  # Call this script recursively for all submodules.
  echo 'Calling '"'"'git submodule foreach '"$FULL_PATH --reentery $opt_init $opt_recursive"' $name $path $sha1 $toplevel'"'"
  git submodule foreach "$FULL_PATH --reentry $opt_init $opt_recursive"' $name $path $sha1 $toplevel'
fi

调用此脚本将与'git submodule update'和 甚至支持--init和--recursive。但是,您可以通过设置'branch'值来配置子模块以结帐并拉取分支;例如:git config -f .gitmodules submodule.NAME.branch master将导致子模块NAME检出并拉出分支主控,而不是当前的SHA1。然后它还会更新父项目以指向该分支的HEAD。