Skip to content

Commit a16a183

Browse files
authored
Merge pull request #118 from smartmobilefactory/git-upmerge
Add upmerge script to make Framework upmerges easier
2 parents 5a23d43 + d3436ab commit a16a183

3 files changed

Lines changed: 113 additions & 0 deletions

File tree

Git/README.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
## Upmerge.sh
2+
3+
The upmerge script is helpful for upmerging branches in the frameworks by automatically merging some files that have conflicts.
4+
5+
It works by using the git merge driver functionality. This allows us to automatically merge some files that normally result in conflicts because they changed on both branches, but we don't actually want to merge the changes.
6+
7+
### Files covered:
8+
9+
- **Podfile.lock**: We always want to take the current version and never want to merge in the one from the branch we are upmerging. The git merge driver here just always picks the current version. This site explains the git merge driver: [https://medium.com/@porteneuve/how-to-make-git-preserve-specific-files-while-merging-18c92343826b](https://medium.com/@porteneuve/how-to-make-git-preserve-specific-files-while-merging-18c92343826b)
10+
- **Podspec**: Here we only want to ignore changes to the version of the podspec. If any other changes were done to the podspec we are upmerging, we have to manually merge them. A custom python script (*podspec-merge-driver.py*) was created to handle detecting the version change.
11+
12+
### Setup
13+
In order to have the merge drivers called for the Podfile.lock and Podspec, the following needs to be added to the *.gitattributes* of the repository.
14+
15+
```
16+
*.podspec merge=podspec-merge-driver
17+
Podfile.lock merge=ours-driver
18+
```
19+
20+
### Usage:
21+
22+
The upmerge script takes two parameters, the branch you are upmerging and the destination branch.
23+
24+
Example: `$ ./upmerge.sh 12.2 13.2`
25+
26+
This upmerges *12.2/master* into *13.2/master*. The script automatically creates a *13.2/upmerge* branch, which you can then push up for a PR.
27+
28+
## podspec-merge-driver.py
29+
This script handles when the podspec has been changed in the branch being upmerged. You don't use this script directly, it is automatically called by git during the merge.
30+
31+
### How it works:
32+
The script takes three arguments as defined by custom merge drivers, see [https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver](https://git-scm.com/docs/gitattributes#_defining_a_custom_merge_driver). These are the three files: ancestor, current, and other. These can be used to do a three-way merge.
33+
34+
The script just looks at the changes done between the ancestor and other. This tells us what was done to the podspec on the branch being upmerged.
35+
36+
Since we only want to ignore when the version number is changed in the podspec being upmerged, we create a unified diff and check the diff to make sure there are no other changes than the version number.
37+
38+
If we detect any other changes, the script returns a non-zero code and this causes git to consider the file not merged. Manual merging of the podspec is then needed.

Git/podspec-merge-driver.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env python
2+
3+
import difflib
4+
import sys
5+
6+
def extract_hunks(unified_diff):
7+
hunks = []
8+
hunk = []
9+
10+
for diff in unified_diff:
11+
# Strip out all whitespace characters
12+
line = "".join(diff.split())
13+
14+
if line == '---' or line == '+++':
15+
continue
16+
elif line.startswith('@@'):
17+
if len(hunk) > 0:
18+
hunks.append(hunk)
19+
hunk = []
20+
else:
21+
hunk.append(line)
22+
23+
if len(hunk) > 0:
24+
hunks.append(hunk)
25+
26+
return hunks
27+
28+
def check_for_only_version_change(hunks):
29+
# If only version is changed, we will have only one hunk
30+
if len(hunks) > 1:
31+
return False
32+
33+
hunk = hunks[0]
34+
35+
# Make sure the hunk only contains the version change
36+
for line in hunk:
37+
if not '.version=' in line:
38+
return False
39+
40+
return True
41+
42+
43+
# Create unified diff between ancestor podpsec and other
44+
diff = difflib.unified_diff(open(sys.argv[1]).readlines() ,open(sys.argv[3]).readlines(), n=0)
45+
hunks = extract_hunks(diff)
46+
47+
if check_for_only_version_change(hunks) == True:
48+
# If only versions are different, we will just take the current version
49+
sys.exit(0)
50+
else:
51+
# Other differences require manual merge
52+
sys.exit(1)

Git/upmerge.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
3+
if [ "$#" -ne 2 ]; then
4+
echo "Wrong number of parameters, should be <source branch> <destination branch>. Example: ./upmerge.sh 12.2 13.2"
5+
exit 1
6+
fi
7+
8+
if [[ -n $(git status -s) ]]; then
9+
echo "Git tree is dirty, please commit changes before upmerging"
10+
exit 1
11+
fi
12+
13+
git checkout origin/$2/master
14+
15+
git checkout -b $2/upmerge
16+
17+
git config merge.ours-driver.driver true
18+
git config merge.podspec-merge-driver.driver "./Submodules/SMF-iOS-CommonProjectSetupFiles/Git/podspec-merge-driver.py %O %A %B"
19+
20+
git merge origin/$1/master --no-edit
21+
22+
git config --unset merge.ours-driver.driver
23+
git config --unset merge.podspec-merge-driver.driver

0 commit comments

Comments
 (0)