使用当前分支子目录的未提交内容破坏另一个 git 分支

Clobber another git branch with uncommitted contents of current branch subdirectory

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

我不想将 _site/ 提交到 gh-pages 分支,只有 web-site分支.

我目前的流程涉及:

(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 构建并在我提交到第一个分支时自动提交到第二个分支的挂钩的形式?

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

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

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

完全未经测试,但应该可以让您入门:

#! /bin/sh

# commit-dir-to-branch: given a directory () and branch
# name (), 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=""
[ -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=""
fullbranch=$(git rev-parse --symbolic-full-name "") || 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

感谢 ,我能够创建一个经过全面测试的解决方案,它完全符合我的需要:

#! /usr/bin/env bash

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

  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'