Jean,
Thanks for your very enlightening perspective!
Regarding issue 2 (that the patch file is up to date) I think
that's//precisely the issue. Mentally I think to quilt refresh
immediately after doing work that I want to record in quilt, just like I
git commit immediately after doing work that I want to commit in git.
Consequently I find it very easy to forget to pop -a before every
non-quilt modification because I'm not mentally in the context of quilt.
For the purposes of this sync command I'll exclude all cases where part
of M2 should be added to the patch file and part should not, but I don't
think that exclusion diminishes the use case.
[ side note: part of why I got into this in the first place is that
my shop uses SVN which doesn't have client side pre-commit hooks. I
think a feature like sync, if it works, would expand the use cases for
quilt. ]
Issue 1 is easy: update the caches for all applied patches. 'patch -R'
to unapply the current patch, what's left goes into the cache, then pop
to correctly remove the patch and go to the next one in the stack. Rinse
and repeat for all applied patches. Then re-apply all of the patches
that had been applied. There is no cache for any patches that weren't
applied at the time of the sync operation so that's already taken care of.
The result is that the .pc/{patch}/files have all been rewritten to
include the new modifications as if the modifications had happened
before the first patch in the stack, like fast-forwarding a git tracking
branch.
I've attached a functional attempt. I haven't tested any of the failure
cases, or complex cases, but it works pretty well with a multi-patch
series in a relatively trivial project. I'm curious to know what you think.
Cheers,
Mike
On 7/18/2017 5:24 AM, Jean Delvare wrote:
Hi Mike,
On Fri, 14 Jul 2017 18:08:09 -0400, tikkoneus wrote:
I just discovered quilt and I think it's a great tool. I've learned just
enough to be dangerous so I'd like some advice before proceeding.
One of my use cases is using it alongside a VCS (primarily svn or git)
to manage personal or local modifications which don't belong in the VCS.
I kind of do the same (to prepare patch series before I actually commit
them, but the situation is the same.)
This breaks quilt quickly when any modifications (git pull / svn update
/ hackity-hack) are made to quilt-tracked files but those modifications
shouldn't be added to the quilt patch (which is what will happen on
quilt refresh). One can advise quilt pop before any operations that
might possibly affect quilt files,
Indeed.
but it's not always possible
Why not?
and if you forget then it gets messy.
Hell yes. That's indeed a real problem for that kind of setup, to which
no solution exists to my knowledge.
The pdf doc even calls out that it may be
possible to resynchronize the index but it's probably worth starting
with a new scratch working directory.
Not sure what you mean... Quilt doesn't even have the notion of index,
merely only a tree of backed up files. Which part of the pdf
documentation are you referring to?
Example: Create a quilt patch P. Create file F and 'quilt add' it, which
copies the current version to the index. Make modification M1 and quilt
refresh which creates a patchfile. Now some other modification M2
happens to F /while M1 is applied /and you don't want M2 to be included
in P. The trouble is that quilt starts by verifying that F + P = working
copy of F, which it won't.
I'm picturing 'quilt sync' which is essentially "pop && replace index &&
push", where the pop operation uses "patch -R" to reverse the given
patch from the /working /copy of F. That would leave F + M1 + M2 - M1 =
F + M2. Copy that version of the file into the index, then push M1, and
now M1 is in fact the only patch on top of the index. 'quilt refresh'
after a sync operation should do nothing.
My questions are:
* Should I be doing this at all? (Am I missing something obvious or
fundamental about how quilt works? Will this abuse or break the
database? Has this already been considered and rejected for good
reasons? Is there a better tool or better way to do what I'm trying
to do?)
I am worried by two limitations of such a "sync" command which would
probably make it as dangerous as the situation you are trying to avoid
in the first place:
1* You assume that there is only one (quilt) patch applied. What if
several (quilt) patches are applied (with a possible overlap of
modified files)?
2* You assume that the applied (quilt) patch is up-to-date, that is, M1
matches the patch file. If this is not the case (that is, other changes
were made to F and "quilt refresh" was not called yet) then after a
"git pull" there is no way for quilt to differentiate between the local
changes you forgot to refresh and the changes pulled from git / svn /
whatever.
This means you would have to remember to call "quilt refresh" before
"git pull", and to call "quilt sync" afterward. I can't see the benefit
compared to the current situation where you have to remember to call
"quilt pop --refresh" before and "quilt push" afterward.
* Any tips on how to go about implementing it?
If you are going to spend any time on this, I would advise implementing
pre-pull/post-pull hooks in git. Git already has a bunch of hooks (see
man 5 githooks) but surprisingly not these. It may be possible to abuse
the post-checkout hook as post-pull (didn't test) but without the first
half it isn't that useful.
If we had such hooks, we could write down the top (quilt) patch name
somewhere then invoke "quilt pop -a" before pulling and "quilt push
$oldtop" after pulling. Straightforward and safe.
I'm happy to submit a pull request but I want to make sure it's a good
idea and I approach it correctly.
I'm afraid you are trying to fix the problem at the wrong place of the
chain.
#! /bin/bash
# This script 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.
#
# See the COPYING and AUTHORS files for more details.
# Read in library functions
if [ "$(type -t patch_file_name)" != function ]
then
if ! [ -r $QUILT_DIR/scripts/patchfns ]
then
echo "Cannot read library $QUILT_DIR/scripts/patchfns" >&2
exit 1
fi
. $QUILT_DIR/scripts/patchfns
fi
usage()
{
printf $"Usage: quilt sync [-hqv]\n"
if [ x$1 = x-h ]
then
printf $"
Synchronize cache when working directory files have changed (e.g. by
a VCS or manual editing) and those changes should not be picked up by
quilt. Use 'patch -R' to unapply each applied patch from the working
copy, use the result to replace the cache in the .pc folder, and then
continue removing any other applied patches. Finish by reapplying any
patches that had been applied.
sync has the effect of 'ignoring' all changes that since the last
refresh operation. sync is idempotent: running it multiple times will
have no further effect.
sync comes in particularly handy if you forget to pop all patches
before modifications to quilt-tracked files because without sync a
pop operation will fail.
"
exit 0
else
exit 1
fi
}
list_patches()
{
local n patches
patches=( $(applied_patches) )
for ((n=${#patches[@]}-1; n>=0; n--))
do
if [ -n "$number" ]
then
(( number-- > 0 )) || break
fi
[ "${patches[n]}" = "$stop_at_patch" ] && break
echo "${patches[n]}"
done
}
sync_patch()
{
local patch=$1 status=0
trap "status=1" SIGINT
local patch=$1
local patch_file=$(patch_file_name "$patch")
local workdir=$(gen_tempfile -d quilt) status=0
if [ -d "$QUILT_PC/$patch" ]
then
local prefix=$PWD/
if ! ( echo $(files_in_patch "$patch") | \
$QUILT_DIR/scripts/backup-files -B "$workdir/" -c -s -f
- )
then
printf $"Failed to copy files to temporary directory\n"
>&2
rm -rf $workdir
return 1
fi
fi
local failed
if [ -s "$patch_file" ]
then
cat_file "$patch_file" \
| patch -R -d $workdir $QUILT_PATCH_OPTS \
$(patch_args "$patch") --no-backup-if-mismatch \
-f >/dev/null 2>/dev/null || failed=1
fi
if [ -n "$failed" ]
then
printf $"Couldn't cleanly unapply patch $patch_file\n" \
"$(print_patch "$patch")" >&2
rm -rf $workdir
return 1
fi
printf $"Updating cache for $patch_file\n"
local file
for file in $(files_in_patch "$patch")
do
cp -f "$workdir/$file" "$QUILT_PC/$patch/"
done
rm -rf $workdir
trap - SIGINT
return $status
}
options=`getopt -o qvh -- "$@"`
if [ $? -ne 0 ]
then
usage
fi
eval set -- "$options"
while true
do
case "$1" in
-q)
opt_quiet=1
shift ;;
-v)
opt_verbose=1
shift ;;
-h)
usage -h ;;
--)
shift
break ;;
esac
done
# ALWAYS prompt for confirmation before rewriting history ...
read -p "
Ignore all modifications that haven't been staged with 'quilt refresh'?
This will rewrite history for all currently applied patches. [n] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]
then
:
else
exit 1
fi
[ -n "$opt_quiet" ] && silent=-s
[ -z "$opt_verbose" ] && silent_unless_verbose=-s
top=$(top_patch)
if ! patches=$(list_patches) 2>&1
then
exit 1
elif [ -z "$patches" ]
then
printf $"No patches currently applied\n" >&2
exit 2
fi
# We will update the list of applied patches, which in turn will disable the
# consistency check. Enable it again if needed.
if [ -z "$opt_all" -a ! "$DB" -nt "$SERIES" ] && ! consistency_check
then
rearm_check=1
fi
for patch in $patches
do
if ! sync_patch "$patch"
then
exit 1
fi
quilt pop -q >/dev/null 2>/dev/null
done
# reapply all patches
for patch in $patches
do
quilt push -q >/dev/null 2>/dev/null
done
_______________________________________________
Quilt-dev mailing list
[email protected]
https://lists.nongnu.org/mailman/listinfo/quilt-dev