Project

General

Profile

Git » History » Version 4

Adam Sutton, 2013-02-01 12:36

1 1 Adam Sutton
h1. Git for TVH Dummies
2
3
As I get quite a few people asking me what the right way to work with git is, in particular in relation to submitting patches upstream, I thought it might be a good idea to write a quick wiki entry to help with some common tasks.
4
5
I'm also fairly new to git, I'd only touched it occasionally before getting involved in Tvheadend, but I've now been using it solidly for about a year. So while I'm by no means an expert, I'll at least point out some of the things I've learnt over that year.
6
7
h2. Github
8
9 3 Adam Sutton
Tvheadend hosts its primary repository on "github":https://github.com, this is a useful community site as not only does it provide basic git hosting but also some useful tools for managing the project. This includes the ability for users to create public forks, submit Pull Requests and to comment on commits and other things.
10 1 Adam Sutton
11
The main project page can be found at https://github.com/tvheadend/tvheadend.
12
13
If you don't intend to actively contribute to the development you can simply clone the repository for the purpose of [[Building]] and the rest of this article is probably not relevant. However should you later decide you do want to push stuff back upstream then there are some useful hints below.
14
15
h2. Forking
16
17
The first thing you should do if you intend to actively develop and push features/fixes upstream is to create a public fork on "github":https://github.com (you can use other services, but it won't fit as well with the general project workflow and the [[Team]] may get grumpy!).
18
19 2 Adam Sutton
To create the fork simply click on the fork icon: !fork.png!
20
21
This will create a new personal fork on github, which will allow you to publish your own changes etc.
22
23
You will also need to add an SSH key to your account to be able to push changes to your fork. If you're unsure how to do this please visit the "github ssh help page":https://help.github.com/articles/generating-ssh-keys.
24
25
Once that is all done you should create a clone of your repository using the SSH access URL (this will give you push access):
26
27
!clone.png!
28
29
<pre>
30
git clone [email protected]:USERNAME/tvheadend.git
31
</pre>
32
33
h3. Fixing upstream clone
34
35
If you have already cloned the upstream (tvheadend/tvheadend.git) repository and now want to create you're own github fork, while still retaining your local repository (possibly with commits you've already made). First create the github fork as above, and instead of cloning that repository do the following within your existing local repository:
36
37
<pre>
38
git remote rename origin upstream
39
git remote add origin SSH_URL
40
git fetch origin
41 1 Adam Sutton
git branch --set-upstream master origin/master
42 3 Adam Sutton
</pre>
43
44
h2. Branches
45
46
It is highly recommended that when you're looking to make changes, especially those you eventually want to submit upstream, that you create a branch.
47
48
There are several ways to create branches within git, but the two most common that I use are:
49
50
<pre>
51
git branch BRANCHNAME
52
</pre>
53
54
and
55
56
<pre>
57
git checkout -b BRANCHNAME
58
</pre>
59
60
This will both create a new branch (called BRANCHNAME) from the currently HEAD. The only difference is the second command will also switch you to the newly created branch.
61
62
If at any time you want to checkout another (existing) branch, do the following:
63
64
<pre>
65
git checkout BRANCHNAME
66
</pre>
67
68
Finally should you want to create a local branch from an existing branch on another fork (such as the upstream tvheadend fork), you can do the following:
69
70
<pre>
71
git checkout -t REMOTENAME/BRANCHNAME
72
</pre>
73
74
This will create a new local branch, with the same name as the remote branch, set it up to track (this means git will among other things tell you the status of your branch relative to the tracked version) and switch to the new branch.
75
76
To publish this branch to your public repository, as always with git there are a number of different ways of doing this. However for simplicity I usually do the following:
77
78
<pre>
79
git push -u origin HEAD
80
</pre>
81
82
This will publish a new branch to your public repository, using the same name as the local branch. It will also set the local branch to track the remote one.
83
84
If you need to send subsequent updates, you can simply do the following:
85
86
<pre>
87
git push
88
</pre>
89
90
Note: Both of the above commands assume that you've already checked out the branch you want to publish.
91
92
h2. Pull Requests
93
94
Eventually you've hopefully created some wonderful new feature or fixed some horrendous bug and you want to share that with the rest of the project. The way this is done is by creating a Pull Request (PR for short).
95
96
A PR is basically a way of saying "hey I've got this cool code, please include it upstream". The development team (or whoever you submit the PR to) can then review your commit, will possibly make comments and ask for changes. And hopefully, if the change is a good one, it will eventually be pulled into the upstream fork and the rest of the world will benefit.
97
98
To begin the PR process, you should hopefully already have a branch that you intend to submit. If not create one now, it'll save you hassle later. The reason being that when you submit a PR you're basically saying pull from this branch, so any commits you add to that branch will automatically be added to the PR. And then make sure this has been published to your public fork.
99
100
If you visit your github project page, you should now see something like this:
101
102
!newbranch.png!
103
104
Click the "Pull Request" button, fill in the form and hit "Send Pull Request". And that's it, code submitted and ready for review.
105
106
h3. Rebasing
107
108
One thing that you should really think about doing before submitting a PR is to clean up the branch, if you don't you'll mostly likely be asked to when you do submit it.
109
110
The bare minimum you should look to do is rebase your commits on top of the current upstream master. This ensures that the code will cleanly merge and that no conflicts exist. It will also make the commit history cleaner and easier to review.
111
112
To do the rebasing, run the following command:
113
114
<pre>
115
git rebase upstream/master
116
</pre>
117
118
You could also squash some commits, this can be especially useful if the branch is littered with lots of commits as you to and fro your way to a solution (mine certainly are usually like that!). The way I usually do this is to use the interactive rebase tool:
119
120
<pre>
121
git rebase -i upstream/master
122
</pre>
123
124
This will present you with a list of your commits, something like:
125
126
<pre>
127
pick 46f2170 update readme date
128
129
# Rebase 2e25766..46f2170 onto 2e25766
130
# Some helpful info...
131
</pre>
132
133
From here you can reorder commits, by simply moving the lines around, squash commits (change pick to fixup or f), remove commits completely (delete the line) or simply change the commit message (change pick to reword or r). Save the file and git will start to apply the changes.
134
135
If the process encounters problems, such as conflicts, then you will need to intervene. The conflicting files will need to be edited to resolve the conflicts, then added back into the commit and finally the rebase continued:
136
137
<pre>
138
edit FILE(s) - manually resolve conflicts
139
git add FILE(s)
140
git rebase --continue
141
</pre>
142
143
How you go about resolving conflicts is down to you.
144
145
It's also worth noting that when you rebase things you're changing history and this may cause problems when trying to push to a remote (if the commits you've modified were already upstream). To resolve this you may be forced to forcefully push the updates, using:
146
147
<pre>
148
git push -f
149
</pre>
150
151
h3. Changes
152
153
Should you want to make changes, or be asked by the upstream [[Team]], then you will need to first make these in the local copy of the branch used for the PR. You then simply publish those changes upstream:
154
155
<pre>
156
git push
157 2 Adam Sutton
</pre>
158 4 Adam Sutton
159
h2. Remote's
160
161
Remote's were briefly mentioned in the earlier sections without really making it clear what they are. In essence, a remote is simply another git repository/fork that is not the local one. Because of the distributed nature of git, you can easily interact with numerous forks at the same time. Pulling change from one and pushing to another etc.
162
163
Normally when working with github (and other hosted solutions) you will normally have 1 or 2 remotes by default:
164
165
<pre>
166
origin - This is the hosted/public copy that your local fork is notionally attached to.
167
upstream - This is typically the hosted/public copy of the parent of origin.
168
</pre>
169
170
There is nothing particularly special about the names origin and upstream, they are simply convention. But I'd recommend sticking with that convention.
171
172
You can also add any other repository you like to your list of remotes and that will give you the ability to pull and push (depending on your access) to those repositories. For example I've currently got this horrible mess of remotes:
173
174
<pre>
175
adamsutton	[email protected]:adamsutton/tvheadend.git (fetch)
176
adamsutton	[email protected]:adamsutton/tvheadend.git (push)
177
andyb2000	git://github.com/andyb2000/tvheadend.git (fetch)
178
andyb2000	git://github.com/andyb2000/tvheadend.git (push)
179
bombadil	aps@home:Workspace/xbmc/tvheadend/tvheadend (fetch)
180
bombadil	aps@home:Workspace/xbmc/tvheadend/tvheadend (push)
181
btbn	        git://github.com/BtbN/tvheadend.git (fetch)
182
btbn	        git://github.com/BtbN/tvheadend.git (push)
183
krka	        git://github.com/krka/tvheadend.git (fetch)
184
krka	        git://github.com/krka/tvheadend.git (push)
185
manio	        git://github.com/manio/tvheadend.git (fetch)
186
manio	        git://github.com/manio/tvheadend.git (push)
187
origin	        [email protected]:tvheadend/tvheadend.git (fetch)
188
origin	        [email protected]:tvheadend/tvheadend.git (push)
189
tornblom	https://github.com/john-tornblom/tvheadend.git (fetch)
190
tornblom	https://github.com/john-tornblom/tvheadend.git (push)
191
</pre>
192
193
It includes my own github fork, the fork on my TVH server (bombadil) and several user repositories I've interacted with recently. Its worth noting that I have no upstream. This is because this is my fork of the tvheadend/tvheadend.git repository, which as the root of all the forks does not itself have a parent.
194
195
To add a new remote simply do the following:
196
197
<pre>
198
git remote add REMOTENAME REMOTEURL
199
</pre>
200
201
You can then sync you local copy of that repository (yes you have all the info for each repository stored locally, though due to the way git is built most of it will already exist on your disk and not require lots of extra space):
202
203
<pre>
204
git fetch REMOTENAME
205
</pre>
206
207
If you want to checkout a remote branch, maybe to have a quick play, you can simply do:
208
209
<pre>
210
git checkout REMOTENAME/BRANCHNAME
211
</pre>
212
213
This will created what is known as a "detached HEAD", it means that its not part of a branch and so you shouldn't make commits (as they'll be lost when you switch to another branch). If you want to create a new branch from the detached state, you can simply do:
214
215
<pre>
216
git checkout -b BRANCHNAME
217
</pre>