shithub: riscv

ref: 1b09060f468f530af2f4ef75441a40084e912e54
dir: /sys/src/cmd/git/branch/

View raw version
#!/bin/rc -e
rfork en
. /sys/lib/git/common.rc

gitup

flagfmt='a:listall, b:baseref ref, d:delete, n:newbr, s:stay, m:merge, M:nomod'
args='[branch]'
eval `''{aux/getflags $*} || exec aux/usage

modified=()
deleted=()

if(~ $#* 0){
	if(~ $#listall 0)
		awk '$1=="branch"{print $2}' < $gitfs/ctl
	if not
		cd .git/refs/ && walk -f heads remotes
	exit
}
if(! ~ $#* 1)
	exec aux/usage

branch=$1
if(~ $branch refs/heads/*)
	new=$name
if not if(~ $branch heads/*)
	new=refs/$branch
if not
	new=refs/heads/$branch

orig=`{git/query HEAD}
if (~ $#baseref 1)
	base=`{git/query $baseref} || exit 'bad base'
if not if(~ $#newbr 0)
	base=`{git/query $new}
if not
	base=`{git/query HEAD}

if(~ $#newbr 0){
	if(! ~ $#baseref 0)
		die update would clobber $branch with $baseref
	baseref=`$nl{echo -n $new | sed s@refs/heads/@refs/remotes/origin/@}
	if(! test -e .git/$new)
		if(! base=`{git/query $baseref})
			die could not find branch $branch
}
modified=`$nl{git/query -c HEAD $base | grep '^[^-]' | subst '^..'}
deleted=`$nl{git/query -c HEAD $base | grep '^-' | subst '^..'}

# if we delete the current branch without switching, bad things happen
if(~ $delete 1 && ~ `{git/query HEAD} `{git/query $branch})
	die 'cannot delete current branch'
# if we're not merging, don't clobber existing changes.
if(~ $#merge 0 && ~ $#delete 0){
	if(! ~ $#modified 0 || ! ~ $#deleted 0){
		git/walk -fRMA $modified $deleted || 
			die 'uncommitted changes would be clobbered'
	}
}
if(~ $delete 1){
	rm -f .git/$new
	echo 'deleted branch' $new
	exit
}
commit=`{git/query $base} || die 'branch does not exist:' $base
if(~ $new */*)
	mkdir -p .git/`{basename -d $new}
if(! ~ $#stay 0){
	echo $commit > .git/$new
	exit
}
basedir=`{git/query -p $base}
dirtypaths=()
if(! ~ $#modified 0 || ! ~ $#deleted 0)
	dirtypaths=`$nl{git/walk -cfRMA $modified $deleted}
if(~ $#dirtypaths 0)
	cleanpaths=($modified $deleted)
if not {
	cleanpaths=()
	for(p in $modified $deleted)
		if(! ~ $p $dirtypaths)
			cleanpaths=($cleanpaths $p)
}

echo $commit > .git/$new
for(m in $cleanpaths){
	d=`$nl{basename -d $m}
	mkdir -p $d
	# Modifications can turn a file into
	# a directory, or vice versa, so we
	# need to delete and copy the files
	# over.
	a=dir
	b=dir
	if(test -f $m)
		a=file
	if(test -f $basedir/tree/$m)
		b=file
	if(! ~ $a $b){
		rm -rf $m
		echo R NOQID 0 $m >> .git/INDEX9
	}
	if(~ $b file){
		cp -x -- $basedir/tree/$m $m
		echo T NOQID 0 $m >> .git/INDEX9
		touch $m
	}
}

for(ours in $dirtypaths){
	common=$gitfs/object/$orig/tree/$ours
	theirs=$gitfs/object/$base/tree/$ours
	merge1 $ours $ours $common $theirs
}

for(d in $deleted){
	if(! test -d $d){
		rm -f $d
		echo R NOQID 0 $d >> .git/INDEX9
	}
}

echo ref: $new > .git/HEAD
echo $new: `{git/query $new}
exit ''