কয়েক বছর আগে আমি এই ধরণের জিনিস পরিচালনা করতে কিছু লিখেছিলাম। (উন্নতির জন্য মন্তব্য অবশ্যই স্বাগত, তবে খুব বেশি বিচার করবেন না - এটি অনেক দিন আগে! আমি পার্লকে এখনও জানতাম না!)
এটি আরও স্থির পরিস্থিতির জন্য বোঝানো হয়েছে - আপনি ফর্মটির কনফিগার প্যারামিটার সেট করে এটি কনফিগার করেন branch.<branch>.autorebaseparent
। এটি এমন কোনও শাখাকে স্পর্শ করবে না যার কনফিগার প্যারামিটার সেট নেই। যদি এটি আপনি না চান তবে আপনি খুব বেশি ঝামেলা ছাড়াই সম্ভবত যেখানে এটি চান সেখানে হ্যাক করতে পারেন। আমি গত দু'বছরে সত্যিই এটি খুব বেশি ব্যবহার করি নি, তবে আমি যখন এটি ব্যবহার করেছি তখন সর্বদা এটি যথেষ্ট নিরাপদ এবং স্থিতিশীল বলে মনে হয়েছিল, ভর স্বয়ংক্রিয় রিবেসিংয়ের মাধ্যমে এটি সম্ভব।
সুতরাং এটি এখানে। আপনার কাছে ডাকা একটি ফাইলে এটি সংরক্ষণ করে ব্যবহার git-auto-rebase
করুন PATH
। বাস্তবের -n
চেষ্টা করার আগে ড্রাই ড্রাই ( ) বিকল্পটি ব্যবহার করা সম্ভবত এটি একটি ভাল ধারণা । আপনার সত্যিকারের চেয়ে এটি আরও কিছুটা বিশদ হতে পারে তবে এটি আপনাকে কীভাবে পুনর্নির্মাণের চেষ্টা করতে চলেছে এবং কী হবে তা আপনাকে প্রদর্শন করবে। আপনাকে কিছুটা দুঃখ বাঁচাতে পারে।
#!/bin/bash
CACHE_DIR=.git/auto-rebase
TODO=$CACHE_DIR/todo
TODO_BACKUP=$CACHE_DIR/todo.backup
COMPLETED=$CACHE_DIR/completed
ORIGINAL_BRANCH=$CACHE_DIR/original_branch
REF_NAMESPACE=refs/pre-auto-rebase
print_help() {
echo "Usage: git auto-rebase [opts]"
echo "Options:"
echo " -n dry run"
echo " -c continue previous auto-rebase"
echo " -a abort previous auto-rebase"
echo " (leaves completed rebases intact)"
}
cleanup_autorebase() {
rm -rf $CACHE_DIR
if [ -n "$dry_run" ]; then
git for-each-ref --format="%(refname)" $REF_NAMESPACE |
while read ref; do
echo git update-ref -d $ref
done
else
git for-each-ref --format="%(refname)" $REF_NAMESPACE |
while read ref; do
git update-ref -d $ref
done
fi
}
get_config_relationships() {
mkdir -p .git/auto-rebase
IFS=$'\n'
git config --get-regexp 'branch\..+\.autorebaseparent' | \
awk '{
child=$1
sub("^branch[.]","",child)
sub("[.]autorebaseparent$","",child)
if (parent[child] != 0) {
print "Error: branch "child" has more than one parent specified."
error=1
exit 1
}
parent[child]=$2
}
END {
if ( error != 0 )
exit error
# check for cycles
for (child in parent) {
delete cache
depth=0
cache[child]=1
cur=child
while ( parent[cur] != 0 ) {
depth++
cur=parent[cur]
if ( cache[cur] != 0 ) {
print "Error: cycle in branch."child".autorebaseparent hierarchy detected"
exit 1
} else {
cache[cur]=1
}
}
depths[child]=depth" "parent[child]" "child
}
n=asort(depths, children)
for (i=1; i<=n; i++) {
sub(".* ","",children[i])
}
for (i=1; i<=n; i++) {
if (parent[children[i]] != 0)
print parent[children[i]],children[i]
}
}' > $TODO
if grep -q '^Error:' $TODO; then
cat $TODO
rm -rf $CACHE_DIR
exit 1
fi
cp $TODO $TODO_BACKUP
}
get_relationships() {
if [ -n "$continue" ]; then
if [ ! -d $CACHE_DIR ]; then
echo "Error: You requested to continue a previous auto-rebase, but"
echo "$CACHE_DIR does not exist."
exit 1
fi
if [ -f $TODO -a -f $TODO_BACKUP -a -f $ORIGINAL_BRANCH ]; then
if ! cat $COMPLETED $TODO | diff - $TODO_BACKUP; then
echo "Error: You requested to continue a previous auto-rebase, but the cache appears"
echo "to be invalid (completed rebases + todo rebases != planned rebases)."
echo "You may attempt to manually continue from what is stored in $CACHE_DIR"
echo "or remove it with \"git auto-rebase -a\""
exit 1
fi
else
echo "Error: You requested to continue a previous auto-rebase, but some cached files"
echo "are missing."
echo "You may attempt to manually continue from what is stored in $CACHE_DIR"
echo "or remove it with \"git auto-rebase -a\""
exit 1
fi
elif [ -d $CACHE_DIR ]; then
echo "A previous auto-rebase appears to have been left unfinished."
echo "Either continue it with \"git auto-rebase -c\" or remove the cache with"
echo "\"git auto-rebase -a\""
exit 1
else
get_config_relationships
fi
}
check_ref_existence() {
local parent child
for pair in "${pairs[@]}"; do
parent="${pair% *}"
if ! git show-ref -q --verify "refs/heads/$parent" > /dev/null ; then
if ! git show-ref -q --verify "refs/remotes/$parent" > /dev/null; then
child="${pair#* }"
echo "Error: specified parent branch $parent of branch $child does not exist"
exit 1
fi
fi
if [ -z "$continue" ]; then
if git show-ref -q --verify "$REF_NAMESPACE/$parent" > /dev/null; then
echo "Error: ref $REF_NAMESPACE/$parent already exists"
echo "Most likely a previous git-auto-rebase did not complete; if you have fixed all"
echo "necessary rebases, you may try again after removing it with:"
echo
echo "git update-ref -d $REF_NAMESPACE/$parent"
echo
exit 1
fi
else
if ! git show-ref -q --verify "$REF_NAMESPACE/$parent" > /dev/null; then
echo "Error: You requested to continue a previous auto-rebase, but the required"
echo "cached ref $REF_NAMESPACE/$parent is missing."
echo "You may attempt to manually continue from the contents of $CACHE_DIR"
echo "and whatever refs in refs/$REF_NAMESPACE still exist, or abort the previous"
echo "auto-rebase with \"git auto-rebase -a\""
exit 1
fi
fi
done
}
create_pre_refs() {
local parent prev_parent
for pair in "${pairs[@]}"; do
parent="${pair% *}"
if [ "$prev_parent" != "$parent" ]; then
if [ -n "$dry_run" ]; then
echo git update-ref "$REF_NAMESPACE/$parent" "$parent" \"\"
else
if ! git update-ref "$REF_NAMESPACE/$parent" "$parent" ""; then
echo "Error: cannot create ref $REF_NAMESPACE/$parent"
exit 1
fi
fi
fi
prev_parent="$parent"
done
}
perform_rebases() {
local prev_parent parent child
for pair in "${pairs[@]}"; do
parent="${pair% *}"
child="${pair#* }"
head -n 1 $TODO >> $COMPLETED
sed -i '1d' $TODO
if [ -n "$dry_run" ]; then
echo git rebase --onto "$parent" "$REF_NAMESPACE/$parent" "$child"
echo "Successfully rebased $child onto $parent"
else
echo git rebase --onto "$parent" "$REF_NAMESPACE/$parent" "$child"
if ( git merge-ff -q "$child" "$parent" 2> /dev/null && echo "Fast-forwarded $child to $parent." ) || \
git rebase --onto "$parent" "$REF_NAMESPACE/$parent" "$child"; then
echo "Successfully rebased $child onto $parent"
else
echo "Error rebasing $child onto $parent."
echo 'You should either fix it (end with git rebase --continue) or abort it, then use'
echo '"git auto-rebase -c" to continue. You may also use "git auto-rebase -a" to'
echo 'abort the auto-rebase. Note that this will not undo already-completed rebases.'
exit 1
fi
fi
prev_parent="$parent"
done
}
rebase_all_intelligent() {
if ! git rev-parse --show-git-dir &> /dev/null; then
echo "Error: git-auto-rebase must be run from inside a git repository"
exit 1
fi
SUBDIRECTORY_OK=1
. "$(git --exec-path | sed 's/:/\n/' | grep -m 1 git-core)"/git-sh-setup
cd_to_toplevel
get_relationships
OLDIFS="$IFS"
IFS=$'\n'
pairs=($(cat $TODO))
IFS="$OLDIFS"
if [ -z "$continue" ]; then
git symbolic-ref HEAD | sed 's@refs/heads/@@' > $ORIGINAL_BRANCH
fi
check_ref_existence
if [ -z "$continue" ]; then
create_pre_refs
fi
perform_rebases
echo "Returning to original branch"
if [ -n "$dry_run" ]; then
echo git checkout $(cat $ORIGINAL_BRANCH)
else
git checkout $(cat $ORIGINAL_BRANCH) > /dev/null
fi
if diff -q $COMPLETED $TODO_BACKUP ; then
if [ "$(wc -l $TODO | cut -d" " -f1)" -eq 0 ]; then
cleanup_autorebase
echo "Auto-rebase complete"
else
echo "Error: todo-rebases not empty, but completed and planned rebases match."
echo "This should not be possible, unless you hand-edited a cached file."
echo "Examine $TODO, $TODO_BACKUP, and $COMPLETED to determine what went wrong."
exit 1
fi
else
echo "Error: completed rebases don't match planned rebases."
echo "Examine $TODO_BACKUP and $COMPLETED to determine what went wrong."
exit 1
fi
}
while getopts "nca" opt; do
case $opt in
n ) dry_run=1;;
c ) continue=1;;
a ) abort=1;;
* )
echo "git-auto-rebase is too dangerous to run with invalid options; exiting"
print_help
exit 1
esac
done
shift $((OPTIND-1))
case $# in
0 )
if [ -n "$abort" ]; then
cleanup_autorebase
else
rebase_all_intelligent
fi
;;
* )
print_help
exit 1
;;
esac
একটি জিনিস যা আমি খুঁজে পেয়েছি, যেহেতু আমি মূলত এটি সম্বোধন করেছি, তা হ'ল কখনও কখনও উত্তরটি হ'ল আপনি আসলে পুনর্বাসনা করতে চাননি! প্রথমে ডান সাধারণ পূর্বপুরুষে টপিক শাখাগুলি শুরু করার জন্য এবং তার পরে তাদের এগিয়ে যাওয়ার চেষ্টা না করার জন্য কিছু বলার আছে। তবে এটি আপনার এবং আপনার কর্মপ্রবাহের মধ্যে।