aboutsummaryrefslogtreecommitdiffstats
path: root/tool/sync-with-trunk
blob: 00b80c006c697228cb3f2898efdfc9ae3cda0bf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#!/bin/sh
set -e

# Pick changes from Ruby trunk and apply on this repository.
# Note that Git >= 2.5 is required.

sha1_to_rev() { git show -s --format=format:%B $1 | tail -n1 | grep -Po '(?<=@)[0-9]+'; }
rev_to_sha1() { git log --format=format:%H -n1 --grep '^git-svn-id: .*@'$2' ' $1; }

echo "#### Step 0. Fetch Ruby trunk"
git remote | grep '^ruby$' >/dev/null || git remote add ruby https://github.com/ruby/ruby.git
git fetch ruby

BRANCH_EXTRACT=sync/extract
echo "#### Step 1. Sync '$BRANCH_EXTRACT' with 'ruby/trunk'"
[ "$(git branch --list $BRANCH_EXTRACT)" ] || git branch $BRANCH_EXTRACT ruby/trunk
[ ! -d tmp/sync-extract ] && git worktree add tmp/sync-extract $BRANCH_EXTRACT
(
	cd tmp/sync-extract
	git checkout $BRANCH_EXTRACT

	if [ $(git rev-parse HEAD) = $(git rev-parse ruby/trunk) ]; then
		filter_range=
	else
		old_head=$(git rev-parse HEAD)
		echo "Updating '$BRANCH_EXTRACT'... HEAD was $old_head."
		graftpoint="$(rev_to_sha1 ruby/trunk $(sha1_to_rev $old_head)) $old_head"
		grep "^$graftpoint$" $(git rev-parse --git-common-dir)/info/grafts >/dev/null 2>&1 ||
			echo "$graftpoint" >> $(git rev-parse --git-common-dir)/info/grafts
		git reset -q --hard ruby/trunk
		filter_range=$old_head..$BRANCH_EXTRACT
	fi

	echo "## Remove unrelated commits"
	git filter-branch -f --prune-empty --index-filter '
		git rm --cached -qr --ignore-unmatch . &&
		git reset -q $GIT_COMMIT -- ext/openssl test/openssl sample/openssl &&
		git rm --cached -q --ignore-unmatch ext/openssl/depend ext/openssl/openssl.gemspec
	' -- $filter_range ||:

	echo "## Adjust path"
	git filter-branch -f --prune-empty --index-filter '
		git ls-files --stage | \
		    sed "s:\ttest/openssl:\ttest:" | \
		    sed "s:\text/openssl/lib:\tlib:" | \
		    sed "s:\text/openssl/sample:\tsample/openssl:" | \
		    sed "s:\tsample/openssl:\tsample:" | \
		    sed "s:\text/openssl/History.md:\tHistory.md:" | \
		    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
		mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
		:
	' -- $filter_range ||:

	echo "## Fix author/committer email"
	git filter-branch -f --env-filter '
		export GIT_AUTHOR_EMAIL=${GIT_AUTHOR_EMAIL/b2dd03c8-39d4-4d8f-98ff-823fe69b080e/ruby-lang.org}
		export GIT_COMMITTER_EMAIL=${GIT_COMMITTER_EMAIL/b2dd03c8-39d4-4d8f-98ff-823fe69b080e/ruby-lang.org}
	' -- $filter_range ||:

	[ "$graftpoint" ] &&
		sed -ie "/^$graftpoint$/d" $(git rev-parse --git-common-dir)/info/grafts
)

LASY_SYNC_COMMIT=$(git log --format=format:%H -n1 --grep '^Sync-with-trunk: r')
LAST_SYNC_REV=$(git show --format=format:%B $LASY_SYNC_COMMIT | grep -Po '(?<=^Sync-with-trunk: r)[0-9]+$' | tail -n1)
NEXT_SYNC_REV=$(sha1_to_rev $BRANCH_EXTRACT)

[ "$LAST_SYNC_REV" = "$NEXT_SYNC_REV" ] && (
	echo "No changes since last sync; aborting."
	exit 1
)

BRANCH_MERGE=sync/merge-r$NEXT_SYNC_REV
echo "#### Step 2. Rebase '$BRANCH_EXTRACT' on the last sync commit"
[ "$(git branch --list $BRANCH_MERGE)" ] || git branch $BRANCH_MERGE $BRANCH_EXTRACT
[ ! -d tmp/sync-merge ] && git worktree add tmp/sync-merge $BRANCH_MERGE
(
	cd tmp/sync-merge
	git checkout $BRANCH_MERGE
	git reset -q --hard $BRANCH_EXTRACT
	git rebase --onto $LASY_SYNC_COMMIT $(rev_to_sha1 $BRANCH_EXTRACT $LAST_SYNC_REV) $BRANCH_MERGE
)

echo "#### Step 3. Merge '$BRANCH_MERGE' into '$(git rev-parse --abbrev-ref HEAD)'"
commit_message=$(
	commits=$(git log --oneline --format='%H %<(61,trunc)%s' $LASY_SYNC_COMMIT..$BRANCH_MERGE)
	echo "Merge changes from Ruby trunk r$LAST_SYNC_REV..r$NEXT_SYNC_REV"
	echo ""
	echo "* ruby-trunk r$LAST_SYNC_REV..r$NEXT_SYNC_REV: ($(echo "$commits" | wc -l) commits)"
	echo "$commits" | while read line; do
		sha1=$(echo "$line" | cut -f1 -d' ')
		cmsg=$(echo "$line" | cut -f2- -d' ')
		echo "  (r$(sha1_to_rev $sha1)) $cmsg"
	done

	echo ""
	echo "Sync-with-trunk: r$NEXT_SYNC_REV"
)
if git merge --no-ff --no-commit $BRANCH_MERGE; then
	git commit -m "$commit_message"
else
	echo "Merge failed; fix conflict and commit with message:"
	echo ""
	echo "$commit_message"
	exit 1
fi