forked from kollerma/git-submodule-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit-attach-head
executable file
·134 lines (123 loc) · 3.67 KB
/
git-attach-head
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#!/bin/bash -e
## Attaches HEAD if commit and top of branch are identical anyway
## Fast forwards local branch if HEAD matches top of remote branch.
## If argument -w is given: warn if HEAD cannot be attached
## prefer master over other branches
## read input, display help if necessary
if [[ "$@" == *--help* ]]; then
cat<<EOF
Attach HEAD to a branch if possible
This command tries to reattach the head of a git repository to some
branch.
If the HEAD and the top of a branch are identical, then this branch
is checked out. If this is not the case, but the local branch can be
fast forwarded, then the script does so. Prefers "master" over other
branches.
The option -f runs the command
git branch -r --contains HEAD
to find branches that contain the current HEAD and checks out the
first one found.
Usage:
git attach-head [-w] [-f]
-w: warn if HEAD cannot be attached
-f: Guess branch name, and forward to a newer commit.
EOF
exit 0;
fi
## from the git mailinglist:
function git
{
LC_MESSAGES=C command git "$@"
}
export git
## TODO: do some error checking?
## stop if HEAD is a ref already
if (git symbolic-ref -q HEAD > /dev/null) ; then
exit 0
fi
## get arguments
while getopts ":fw" opt; do
case $opt in
w)
w=1
#echo "-f was triggered!" >&2
;;
f)
fopt=1
## echo "-f was triggered!" >&2
;;
\?)
# ignore this
#echo "Invalid option: -$OPTARG" >&2
;;
esac
done
HEAD=`git rev-parse HEAD`
## get first refs for master (prefer master)
branch=`git show-ref master | grep $HEAD | sed 's/.*refs\///' | sed -e '2,$ d'`
if [[ ! "$branch" ]]; then
## ok, allow all refs but HEAD and tags/*, get first match
branch=`git show-ref | grep $HEAD | sed -e 's/.*refs\///' -e '/HEAD/ d' -e '/tags\// d' | sed -e '2,$ d'`
fi
if [[ ! "$branch" ]]; then
if [[ ! "$fopt" ]]; then
if [[ "$w" ]]; then
cat >&2 <<EOF
Warning in $PWD:
Cannot attach HEAD. There are probably unmerged updates available.
Go ("cd") there and use "git -r --contains HEAD" list branches that
contain the current commit. Use "git attach-head -f" to attach to
the first branch automatically. Otherwise switch branches with
"git rcheckout <branchname>".
EOF
fi
else
candidate=`git branch -r --contains HEAD | grep -m 1 -v HEAD`
## remove remote prefix
candidate=${candidate#*/}
if [[ "$w" ]]; then
cat >&2 <<EOF
Warning in $PWD:
Forwarding from commit $HEAD
to newest version in branch "$candidate". Please make sure that this
is the correct branch and commit the change in the supermodules.
EOF
fi
git rcheckout "$candidate"
fi
else
## try to attach head now
branch=${branch#heads/}
##echo "Attaching $PWD to $branch..."
lbranch=${branch#remotes/*/}
if [ "$branch" != "$lbranch" ]; then
## we matched a remote/../ branch
rbranch=${branch#remotes/}
## check if a local branch exists that tracks this branch
tbranch=`git branch -vv | grep "\[$rbranch" | sed -e 's/ \([^ ]*\) .*/\1/' -e '2,$ d'`
if [[ "$tbranch" ]]; then
## check if we can fast forward the corresponding local branch
if (git branch -vv | grep " $tbranch" | grep " ahead " -q); then
## cannot, since local branch is ahead -> exit
if [[ "$w" ]]; then
cat >&2 <<EOF
Warning in $PWD:
Cannot attach HEAD.
The local branch $tbranch is ahead of $rbranch.
EOF
fi
exit 0
fi
lbranch="$tbranch"
else
## there is no local tracking branch for $remote: create one
git branch "$lbranch" "$rbranch" > /dev/null
branch="$lbranch"
fi
fi
git checkout --quiet "$lbranch" > /dev/null
if [ "$branch" != "$lbranch" ]; then
#echo "Fast forwarding local branch"
git merge --quiet --ff-only $HEAD
fi
fi