Exporting changed and added files from a bare repo with no working-tree to a directory for compilation or deployment

153 Views Asked by At

I have a bare repo that developers push their hotfix branches to from their local repo on Windows. When the branch is pushed I trigger a hook to build their changes on Linux. This is easy to do if I create a working-tree for the branch. However, the repo contains 10's of thousands of files and having each developer's hotfix branch create a working-tree for all objects when they are only committing a change to a few is a huge time-sink and drain on the file system.

Is there a way to let the developers push to the bare repo and then in a hook extract only the changed sources to a directory structure so I can have an efficient build process?

Ideas?

Example developer_a pushes his HF1 branch that was branched off the Dev branch back to the remote bare repo on the Linux build server.

In the hook if I perform a "git diff" of the HF1 and the dev branch I can see the list of files that were changed.

diff-tree -r --no-commit-id --name-only HF1..dev

/APP/SOURCE/Program1.cbl

Any attempt to use that file on the above command fails because the working tree does not exist.

I'd like to generate this diff and then extract directly from the repo the files listed in the diff to a target directory.

2

There are 2 best solutions below

1
VonC On

I'd like to generate this diff and then extract directly from the repo the files listed in the diff to a target directory.

That sounds like what Git is already doing natively when it checks out a branch in a working tree already set to a given commit.

If your building working tree is at a certain commit, the hook can trigger a git checkout of the new SHA1 pushed: the working tree will detect changes and updates itself (through a git checkout triggered by the post-receive hook) to update only what is needed.

0
Westend On

Here's a post-receive script I wrote to eliminate the need for a branch to use a working tree for a build triggered off a push of a branch to a build server. This script does the following:

  • Determines the branch being pushed.
  • Identifies the changed source components.
  • Constructs a build tree within the defined build environment.
  • Populates the build tree and triggers the compilation and deployment.

If there are common components such as include files then the master and dev branches require a working-tree. The build environment will concatenate those include directories as required.

The dev push will diff against the master repo while the user branches that were branched from the dev branch will diff against dev.

post-receive hook

#!/bin/bash
###########################################################################

function get_files {
# determine the changed files and extract them from the repo to the build structure.
    git diff-tree -r ${ORIGIN}..${BRANCH} |
        while IFS= read -r line
        do
        COMMIT_ID=$(echo $line | cut -f4 -d" " )
        SOURCE=$(echo $line | cut -f6 -d" " )
            echo "Identified: " ${SOURCE} " Commit: " ${COMMIT_ID}
        TARGET=$(basename ${SOURCE})
        echo "Target : " ${TARGET}  
        echo ${TARGET} >> ${BUILD_PATH}/etc/build.txt

        echo "Extracting source from repo: " $SOURCE
        git show ${COMMIT_ID} > ${BUILD_PATH}/${SOURCE}
    done
}

function build_targets {
    FILES=$(cat ${BUILD_PATH}/etc/build.txt)
    for i in $FILES
    do
        echo "Compiling: " $i
    done
}

function prep_build_tree {
#Check if build structure exists
        if [[ -d ${BUILD_PATH} ]]
        then
# clean source from the local build structre by removing and rebuilding it
            echo "Cleaning old build structure"
            find ${BUILD_PATH} -type f -exec rm -v {} \;
        else
# Create build structure
            echo "Creating build structure"
            mkdir -p ${BUILD_PATH}/APP/SOURCE
            mkdir -p ${BUILD_PATH}/APP/COPY
            mkdir -p ${BUILD_PATH}/etc
            mkdir -p ${BUILD_PATH}/LOADLIB
        fi
}

##############################################################################

read oldrev newrev refname
echo "Old revision: $oldrev"
echo "New revision: $newrev"
echo "Reference name: $refname"

BASE_DIR=/home/mfcobol/SDLC/BUILD/Dev-Build
BRANCH=$(basename $refname)

#determine build type:
#   dev branch performs build using the dev build structure checked against master
#       other branches perform local builds for that branch only checked against dev.
case $BRANCH in

    dev ) BUILD=dev 
        echo "Dev build identified: Branch: "${BRANCH} 
        ORIGIN=master
        BUILD_PATH=${BASE_DIR}/${BUILD}/${BRANCH}
        prep_build_tree
        get_files
        build_targets ;;


    * )   BUILD=user
        echo "User build identified: Branch: "${BRANCH}
        ORIGIN=dev
        BUILD_PATH=${BASE_DIR}/${BUILD}/${BRANCH}
        prep_build_tree
        get_files
        build_targets ;;
esac