Clobber另一个git分支,具有当前分支子目录的未提交内容

时间:2016-03-12 19:25:01

标签: git hook jekyll

我使用 jekyll gh-pages 分支中构建我的网站。我想将生成的内容从_site/目录提交到另一个(本地)分支的根目录(例如,名为 web-site ),替换其所有内容。

我不想将_site/提交到 gh-pages 分支,只提交网站分支。

我目前的流程涉及:

(gh-pages)$ jekyll build --config _config-production.yml
(gh-pages)$ mv _site/ ../
(gh-pages)$ git checkout web-site
(web-site)$ rm -rf * # remove all current contents except dotfiles
(web-site)$ mv ../_site/* . && rmdir ../_site/
(web-site)$ git commit -a

这看起来非常低效且容易出错。有没有办法用一个子目录的未提交内容来破坏另一个分支的内容,最好是以运行jekyll构建的钩子的形式,并且每当我提交第一个分支时自动提交到第二个分支?

2 个答案:

答案 0 :(得分:2)

我对Jekyll一无所知,但是为了在特定分支上进行新的提交而不以任何方式干扰当前分支或暂存区域,您将需要:

  • 设置临时索引文件;
  • 填充该索引文件;
  • 使用git write-tree将其转换为顶级树;
  • 使用git commit-tree从该树进行提交;和
  • 使用git update-ref更新所需的分支名称。

commit-tree步骤之后,您可以放弃临时索引。

完全未经测试,但应该让你开始:

#! /bin/sh

# commit-dir-to-branch: given a directory ($1) and branch
# name ($2), make a new commit on the target branch that
# consists of that directory's contents.

# NB: totally untested!

# Get git script goodies.
. $(git --exec-path)/git-sh-setup

# Make sure target directory exists.
dir="$1"
[ -d "$dir" ] || die "fatal: $dir is not a directory"

# Make sure branch name exists and names an actual branch
# (note: symbolic refs get resolved here, we could check
# and reject a symbolic ref too).
branch="$2"
fullbranch=$(git rev-parse --symbolic-full-name "$2") || exit 1
case "$fullbranch" in
refs/heads/*) ;;
*) die "fatal: $branch does not name a branch"
esac

# Choose new temp index file, make sure to clean it up on
# exit, interrupt, etc.
GIT_INDEX_FILE=$(mktemp) || die "fatal: unable to create temp index"
rm -f $GIT_INDEX_FILE
trap "rm -f $GIT_INDEX_FILE 0 1 2 3 15"
export GIT_INDEX_FILE

# Now fill in the index from the directory.
#
# Note that we don't override ignore files (.git/info/exclude,
# core.excludesFile, etc).  This may be a feature or a bug...
git --work-tree="$dir" add . || die "fatal: error adding $dir"

# Write the tree, and make a commit.  The new commit's parent
# is the commit currently at the head of the target branch.
#
# We probably should allow -m and -F arguments to this script
# for setting the message, rather than just supplying "autocommit"
# here.
tree=$(git write-tree) || die "fatal: error writing tree"
commit=$(git commit-tree -p $fullbranch -m "autocommit from $dir") ||
    die "fatal: error writing commit"

# Finally, update the branch ref.  Finishing the script will
# remove the temporary index.
git update-ref -m "autocommit from $dir" $fullbranch $commit

答案 1 :(得分:0)

感谢torek's answer,我能够创建一个经过全面测试的解决方案,完全满足我的需求:

#! /usr/bin/env bash

build_jekyll_site() {
  # $1 is the expected source branch
  local source_br; source_br=$1
  # $2 is the name of the target branch
  local tgt_br; tgt_br=$2
  # $3 jekyll config file to build
  local config; config=$3

  local cur_branch; cur_branch=$(git rev-parse --symbolic-full-name HEAD) || return 1

  # skip execution on other branches
  [[ $cur_branch == "refs/heads/$source_br" ]] || return 0

  # create message
  local message; message="Jekyll build from $source_br:$(git rev-parse --verify 'HEAD^{commit}' | cut -c1-7)"$'\n'$'\n'"$(git cat-file commit HEAD | sed '1,/^$/d')"

  # import git utils: needed for die, require_clean_work_tree
  . "$(git --exec-path)/git-sh-setup" || return 1

  # ensure target branch exists
  local target_branch; target_branch=$(git rev-parse --symbolic-full-name "$tgt_br" 2>/dev/null) || die "fatal: $tgt_br is not a branch"
  case "$target_branch" in
    refs/heads/*)
      true
      ;;
    *)
      die "fatal: $tgt_br is not a branch"
      ;;
  esac

  # don't build what's not checked in
  require_clean_work_tree

  # check that jekyll config file exists
  [[ -f $config ]] || die "fatal: $config is not a file or does not exist"

  # build using jekyll 3
  local regex
  regex='^jekyll 3[.](0[.][3-9][0-9]*|0[.][1-2][0-9]+|[1-9][0-9]*[.][0-9]+)'
  local jekyll
  jekyll=$(jekyll -v 2>/dev/null)
  [[ $jekyll =~ $regex ]] || die "fatal: requires jekyll >= 3.0.3 to build"

  # prep the working location
  local workdir; workdir=$(mktemp -d --tmpdir jekyll-XXXXXXXXXX) || die "fatal: unable to allocate a temporary directory"
  trap "rm -rf '""$workdir""'" 0 1 2 3 15

  # actually generate the site
  jekyll build --config "$config" --destination "$workdir/_site" --safe || die "fatal: jekyll build failure"

  # prepare and commit to the target branch
  export GIT_INDEX_FILE="$workdir/index"
  git --work-tree="$workdir/_site" add . || die "fatal: error adding $workdir/_site"
  local tree; tree=$(git write-tree) || die "fatal: error writing tree"
  local commit; commit=$(git commit-tree "$tree" -p "$target_branch" -m "$message") || die "fatal: error writing commit"
  git update-ref -m "$message" "$target_branch" "$commit" || die "fatal: error updating ref"

  return 0
}

build_jekyll_site 'gh-pages' 'web-site' '_config-production.yml'