Created
February 10, 2019 05:01
-
-
Save wchargin/3934c1c09812a2ad0e4f2092391e1ac8 to your computer and use it in GitHub Desktop.
wcgit utils for pushing a one-patch-is-one-change local repository to a one-branch-per-change remote (see https://wchargin.github.io/posts/managing-dependent-pull-requests for explanation)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
https://wchargin.github.io/posts/managing-dependent-pull-requests |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# | |
# git-push-to-target: Push this commit to a branch specified in its | |
# commit description. | |
# | |
# Copyright (c) 2018 William Chargin. Released under the MIT license. | |
set -eu | |
usage() { | |
printf 'usage: git push-to-target [[REF...] | --since REVISION]\n' | |
printf ' [(--remote|-r) REMOTE]\n' | |
printf ' [--dry-run|-n] [--help|-h]\n' | |
printf '\n' | |
printf 'Push commits to remote branches specified in their messages.\n' | |
printf '\n' | |
printf '%s\n' '[REF...]' | |
printf ' If explicit revisions are specified, push those commits.\n' | |
printf ' If no revisions are specified, act as if HEAD was given.\n' | |
printf '\n' | |
printf '%s\n' '--since REVISION' | |
printf ' Push those commits reachable from HEAD but not reachable\n' | |
printf ' from REVISION. Incompatible with explicit revisions.\n' | |
printf '\n' | |
printf '%s\n' '(--remote|-r) REMOTE' | |
printf ' Push to REMOTE. Defaults to "origin".\n' | |
printf '\n' | |
printf '%s\n' '(--dry-run|-n), or environment variable DRY_RUN nonempty' | |
printf ' Invoke git-push with --dry-run.\n' | |
printf '\n' | |
printf '%s\n' '--help' | |
printf ' Show this message.\n' | |
printf '\n' | |
printf 'See: git-target-branch(1).\n' | |
} | |
# Read refs from stdin and push them. Stdin must be nonempty. | |
process_refs() { | |
remote="$1" | |
refspecs=( ) | |
while read -r ref; do | |
sha="$(git rev-parse --short --verify "${ref}")" | |
target="$(git target-branch "${sha}")" | |
refspec="${sha}:refs/heads/${target}" | |
refspecs+=( "${refspec}" ) | |
message="$(git show --no-patch --format=%s "${sha}")" | |
printf ' * %s:%s (%s)\n' "${sha}" "${target}" "${message}" | |
done | |
dry_run= | |
if [ -n "${DRY_RUN:-}" ]; then | |
dry_run="--dry-run" | |
fi | |
(set -x; git push $dry_run --force-with-lease "${remote}" "${refspecs[@]}") | |
} | |
main() { | |
since= | |
remote=origin | |
refs=( ) | |
while [ $# -gt 0 ]; do | |
case "$1" in | |
--help|-h) | |
usage | |
exit 0 | |
;; | |
--remote|-r) | |
shift | |
remote="$1" | |
;; | |
--dry-run|-n) | |
DRY_RUN=1 | |
;; | |
--since) | |
shift | |
since="$1" | |
;; | |
*) | |
refs+=( "$1" ) | |
;; | |
esac | |
shift | |
done | |
if [ -n "${since}" ]; then | |
if [ "${#refs[@]}" -ne 0 ]; then | |
printf >&2 'fatal: --since used with explicit revisions\n' | |
return 1 | |
fi | |
ref_list="$(git rev-list --reverse HEAD "^${since}")" | |
printf '%s\n' "${ref_list}" | process_refs "${remote}" | |
elif [ "${#refs[@]}" -gt 0 ]; then | |
printf '%s\n' "${refs[@]}" | process_refs "${remote}" | |
else | |
printf 'HEAD\n' | process_refs "${remote}" | |
fi | |
} | |
main "$@" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
# | |
# git-target-branch: Identify the remote tracking branch specified in a | |
# commit message. | |
# | |
# Copyright (c) 2018 William Chargin. Released under the MIT license. | |
set -eu | |
DIRECTIVE='wchargin-branch' | |
BRANCH_PREFIX='wchargin-' | |
target_branch() { | |
# shellcheck disable=SC1004 | |
awk -v FS=": " -v directive="${DIRECTIVE}" -v prefix="${BRANCH_PREFIX}" ' | |
NR == 1 { summary = $0 } | |
$1 == directive { | |
if (NF == 2 && $2 !~ /[^A-Za-z0-9_.-]/) { | |
found[count++] = $2; | |
} else { | |
printf("bad \"%s\" directive (%s): %s\n", directive, $0, summary) \ | |
>"/dev/stderr"; | |
aborted = 1; | |
exit 1; | |
} | |
} | |
END { | |
if (aborted) exit; | |
if (count == 0) { | |
printf("missing \"%s\" directive: %s\n", directive, summary) \ | |
>"/dev/stderr"; | |
exit 1; | |
} else if (count > 1) { | |
printf("multiple \"%s\" directives: %s\n", directive, summary) \ | |
>"/dev/stderr"; | |
exit 1; | |
} else { | |
printf("%s%s\n", prefix, found[0]); | |
} | |
} | |
' | |
} | |
main() { | |
# TODO: --help | |
src="${1:-HEAD}" | |
if [ "${src}" = '-' ]; then | |
target_branch | |
else | |
git show --no-patch --format=%B "${src}" | target_branch | |
fi | |
} | |
main "$@" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment