#!/bin/bash # SPDX-License-Identifier: GPL-2.0-only # (kgit-checkpoint), (checkpoint and restore for meta-information) # Copyright (c) 2008-2012 Wind River Systems, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 as # published by the Free Software Foundation. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # For consistent behaviour with "grep -w" LC_ALL=C export LC_ALL usage() { cat < [-c] [-r] [-d] [-v] -b: branch that stores checkpointed files -r: restore checkpoint commit -c: create a checkpoint commit -m: checkpoint message (the date will be used if not supplied) -v: verbose : 'restore' or 'create'. equivalent to -r and -c EOF } # command line processing while [ $# -gt 0 ]; do case "$1" in -b|--b) cmd_branch=$2 shift ;; -m|--m) checkpoint_msg="$2" shift ;; -v|--v) verbose=t ;; -r|--r) restoring=t checkpointing= ;; -c|--c) restoring= checkpointing=t ;; -h|--h) usage exit ;; -*) usage exit ;; *) break ;; esac shift done if [ -z "$1" ] ; then if [ -z "$checkpointing" ] && [ -z "$restoring" ]; then usage exit fi fi # source utility functions . `dirname $0`/kgit action=$@ case $action in create) restoring= checkpointing=t ;; restore) restoring=t checkpointing= ;; esac if [ ! -d .git ]; then echo "ERROR. Not a git repository" exit 1 fi # set some defaults if [ -z "$checkpoint_msg" ]; then checkpoint_msg="checkpoint: `date`" fi # save this so we can go back later ... current_branch=`get_current_git_branch` checkpoint_branch= get_meta_dir() { meta_branch=$1 # if there's already a located and logged meta directory, just use that and # return. Otherwise, we'll look around to see what we can find. if [ -f ".metadir" ]; then md=`cat .metadir` echo $md return fi # determine the meta directory name meta_dir_options=`git ls-files -o --directory` for m in $meta_dir_options; do if [ -d "$m/cfg" ]; then md=`echo $m | sed 's%/%%'` fi done # store our results where other scripts can quickly find the answer if [ -n "$md" ]; then echo "$md" > .metadir fi # return the directory to he caller echo $md } checkpoint_branch=$KMETA if [ -n "$cmd_branch" ]; then checkpoint_branch=$cmd_branch fi # verify we have a checkpoint branch and exit if one wasn't found if [ -z "$checkpoint_branch" ]; then echo "[ERROR]: no checkpoint/meta branch found. Either set KMETA or pass it via -b." exit 1 fi git show-ref --quiet --verify -- "refs/heads/$checkpoint_branch" if [ $? -eq 1 ]; then if [ -n "$verbose" ]; then echo "Checkpoint branch [$checkpoint_branch] does not exist, using default meta directory" fi meta_dir=$checkpoint_branch else meta_dir=`get_meta_dir` fi echo $meta_dir if [ -z "$files_to_checkpoint" ]; then dirs_to_checkpoint="$meta_dir/cfg/kernel-*cache $meta_dir/cfg/scratch \ $meta_dir/patches $meta_dir/scripts $meta_dir" fi if [ -n "$checkpointing" ]; then if [ -n "$verbose" ]; then echo "[INFO]: Creating checkpoint on branch $checkpoint_branch" fi # if the branch doesn't already exist. Create it as an orphan. git show-ref --quiet --verify -- "refs/heads/$checkpoint_branch" if [ $? -eq 1 ]; then # create a meta-information branch git checkout --orphan $checkpoint_branch if [ $? != 0 ]; then echo "[ERROR]: orphan branch creation failed" exit -1 fi # remove the unwanted files/directories git rm -rfq `ls -d .gitignore .mailmap * | grep -v $checkpoint_branch` if [ $? != 0 ]; then echo "[ERROR]: git rm -rfq failed" exit -1 fi else git checkout $checkpoint_branch if [ $? != 0 ]; then echo "[ERROR]: checkpoint branch checkout failed" exit -1 fi fi echo "kernel repository meta data base" >> README.txt git add -f README.txt if [ $? != 0 ]; then echo "[ERROR]: git add failed" exit -1 fi git commit -s -m "meta: add README" if [ $? != 0 ]; then echo "[ERROR]: git commit README failed" exit -1 fi # either we just created an orphan branch .. or it already # existed. Either way, iterate the directories that should be added to # the branch and add them. for d in $dirs_to_checkpoint; do count=`git ls-files -dmo $d | wc -l` if [ $count -eq 0 ]; then # if there aren't any untracked files, then there's nothing to commit continue fi git add -f $d if [ $? != 0 ]; then echo "[ERROR]: git add dirs failed" exit -1 fi if [ -f "$d/00-README" ]; then TXT=`mktemp` echo "checkpoint dir: $d" > $TXT echo >> $TXT echo "What follows is the 00-README from dir \"$d\"." >> $TXT echo >> $TXT echo " ----------------------" >> $TXT cat $d/00-README >> $TXT echo " ----------------------" >> $TXT git commit -q -s -F $TXT &> /dev/null if [ $? != 0 ]; then echo "[ERROR]: git commit 00-README failed" exit -1 fi rm -f $TXT else git commit -q -s -m "checkpoint dir: $d" &> /dev/null if [ $? != 0 ]; then echo "[ERROR]: git commit checkpoint dir failed" exit -1 fi fi done if [ -z "$verbose" ]; then q="-q" fi # tag the branch so it can be found later git show-ref --quiet --verify -- "refs/tags/checkpoint-$checkpoint_branch" if [ $? -eq 1 ]; then git tag checkpoint-$checkpoint_branch if [ $? != 0 ]; then echo "[ERROR]: git tag checkpoint failed" exit -1 fi fi # return to the current branch if [ "$checkpoint_branch" != "$current_branch" ]; then git checkout -q $current_branch if [ $? != 0 ]; then echo "[ERROR]: git checkout current failed" exit -1 fi fi else # restoring ... if [ -n "$verbose" ]; then echo "[INFO]: Restoring checkpoint from branch $checkpoint_branch" fi # check if '$meta_dir' is tracked or not. If it is untracked, we don't # have anything to do. meta_dir=`get_meta_dir` if [ -n "$meta_dir" ]; then echo "[INFO]: checkpoint is already restored, nothing to do" exit 0 fi # We consider everything on the checkpoint branch to be part of the stored # state. If the branch was an orphan branch, the merge_base will be zero. In # that case, we just get all commits on the branch via git rev-list merge_base=`git merge-base $checkpoint_branch master` if [ -z "$merge_base" ]; then merge_base=`git rev-list $checkpoint_branch -- | tail -1` fi # save the old branch, and make the data untracked. git checkout -q -f -b $checkpoint_branch-temp $checkpoint_branch &> /dev/null if [ $? != 0 ]; then echo "[ERROR]: git checkout -q -b failed" exit -1 fi git reset --mixed $merge_base &> /dev/null if [ $? != 0 ]; then echo "[ERROR]: git reset mixed failed" exit -1 fi # At this point, we've reset the branch and the meta data is now # reset and can persist when we change the branch, but we need to # make a copy of them to *something* else, or git will complain about # them being clobbered when we switch away. if [ -d "$checkpoint_branch" ]; then checkpoint_dir=$checkpoint_branch else for f in `find -maxdepth 1 -type d -not -name .git -and -not -name . -printf '%f'`; do if [ -d "$f" ]; then # a directory is our meta dir checkpoint_dir=$f fi done fi if [ ! -d ".$checkpoint_dir" ]; then mv $checkpoint_dir .$checkpoint_dir fi # delete our working branch, and return to the original one if [ "$checkpoint_branch" != "$current_branch" ]; then git checkout -f -q $current_branch if [ $? != 0 ]; then echo "[ERROR]: git checkout -q failed" exit -1 fi else git checkout -f -q master if [ $? != 0 ]; then echo "[ERROR]: git checkout -q failed" exit -1 fi fi git branch -D $checkpoint_branch-temp if [ $? != 0 ]; then echo "[ERROR]: git branch -D failed" exit -1 fi # Double check the meta_dir, and write the results for following scripts meta_dir=`get_meta_dir` fi