【问题标题】:Clobber another git branch with uncommitted contents of current branch subdirectory用当前分支子目录的未提交内容破坏另一个 git 分支
【发布时间】:2016-03-12 19:25:00
【问题描述】:

我使用 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 构建并自动提交到第二个分支的钩子的形式?

【问题讨论】:

    标签: git hook jekyll


    【解决方案1】:

    我对 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
    

    【讨论】:

    • 这其中有很多很棒的东西,我什至不知道的 git 命令等等......肯定会尝试一下,让你知道它是否有效!谢谢!
    【解决方案2】:

    感谢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'
    

    【讨论】:

      猜你喜欢
      • 2013-11-04
      • 1970-01-01
      • 2021-12-12
      • 2016-03-23
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      相关资源
      最近更新 更多