File: multiplayer.txt

package info (click to toggle)
gitmagic 20140125-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 2,176 kB
  • ctags: 20
  • sloc: makefile: 92; sh: 38
file content (233 lines) | stat: -rw-r--r-- 8,698 bytes parent folder | download | duplicates (5)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
== Multiplayer Git ==

Initially I used Git on a private project where I was the sole developer.
Amongst the commands related to Git's distributed nature, I needed only *pull*
and *clone* so could I keep the same project in different places.

Later I wanted to publish my code with Git, and include changes from
contributors. I had to learn how to manage projects with multiple developers
from all over the world. Fortunately, this is Git's forte, and arguably its
raison d'ĂȘtre.

=== Who Am I? ===

Every commit has an author name and email, which is shown by *git log*.
By default, Git uses system settings to populate these fields.
To set them explicitly, type:

  $ git config --global user.name "John Doe"
  $ git config --global user.email johndoe@example.com

Omit the global flag to set these options only for the current repository.

=== Git Over SSH, HTTP ===

Suppose you have SSH access to a web server, but Git is not installed. Though
less efficient than its native protocol, Git can communicate over HTTP.

Download, compile and install Git in your account, and create a repository in
your web directory:

 $ GIT_DIR=proj.git git init
 $ cd proj.git
 $ git --bare update-server-info
 $ cp hooks/post-update.sample hooks/post-update

For older versions of Git, the copy command fails and you should run:

 $ chmod a+x hooks/post-update

Now you can publish your latest edits via SSH from any clone:

 $ git push web.server:/path/to/proj.git master

and anybody can get your project with:

 $ git clone http://web.server/proj.git

=== Git Over Anything ===

Want to synchronize repositories without servers, or even a network connection?
Need to improvise during an emergency? We've seen <<makinghistory, *git
fast-export* and *git fast-import* can convert repositories to a single file
and back>>. We could shuttle such files back and forth to transport git
repositories over any medium, but a more efficient tool is *git bundle*.

The sender creates a 'bundle':

 $ git bundle create somefile HEAD

then transports the bundle, +somefile+, to the other party somehow: email,
thumb drive, an *xxd* printout and an OCR scanner, reading bits over the phone,
smoke signals, etc. The receiver retrieves commits from the bundle by typing:

 $ git pull somefile

The receiver can even do this from an empty repository. Despite its
size, +somefile+ contains the entire original git repository.

In larger projects, eliminate waste by bundling only changes the other
repository lacks. For example, suppose the commit ``1b6d...'' is the most
recent commit shared by both parties:

 $ git bundle create somefile HEAD ^1b6d

If done frequently, one could easily forget which commit was last sent. The
help page suggests using tags to solve this. Namely, after you send a bundle,
type:

 $ git tag -f lastbundle HEAD

and create new refresher bundles with:

 $ git bundle create newbundle HEAD ^lastbundle

=== Patches: The Global Currency ===

Patches are text representations of your changes that can be easily understood
by computers and humans alike. This gives them universal appeal. You can email a
patch to developers no matter what version control system they're using. As long
as your audience can read their email, they can see your edits. Similarly, on
your side, all you require is an email account: there's no need to setup an online Git repository.

Recall from the first chapter:

 $ git diff 1b6d > my.patch

outputs a patch which can be pasted into an email for discussion. In a Git
repository, type:

 $ git apply < my.patch

to apply the patch.

In more formal settings, when author names and perhaps signatures should be
recorded, generate the corresponding patches past a certain point by typing:

 $ git format-patch 1b6d

The resulting files can be given to *git-send-email*, or sent by hand. You can also specify a range of commits:

 $ git format-patch 1b6d..HEAD^^

On the receiving end, save an email to a file, then type:

 $ git am < email.txt

This applies the incoming patch and also creates a commit, including information such as the author.

With a browser email client, you may need to click a button to see the email in its raw original form before saving the patch to a file.

There are slight differences for mbox-based email clients, but if you use one
of these, you're probably the sort of person who can figure them out easily
without reading tutorials!

=== Sorry, We've Moved ===

After cloning a repository, running *git push* or *git pull* will automatically
push to or pull from the original URL. How does Git do this? The secret lies in
config options created with the clone. Let's take a peek:

 $ git config --list

The +remote.origin.url+ option controls the source URL; ``origin'' is a nickname
given to the source repository. As with the ``master'' branch convention, we may
change or delete this nickname but there is usually no reason for doing so.

If the original repository moves, we can update the URL via:

 $ git config remote.origin.url git://new.url/proj.git

The +branch.master.merge+ option specifies the default remote branch in
a *git pull*. During the initial clone, it is set to the current branch of the
source repository, so even if the HEAD of the source repository subsequently
moves to a different branch, a later pull will faithfully follow the
original branch.

This option only applies to the repository we first cloned from, which is
recorded in the option +branch.master.remote+. If we pull in from other
repositories we must explicitly state which branch we want:

 $ git pull git://example.com/other.git master

The above explains why some of our earlier push and pull examples had no
arguments.

=== Remote Branches ===

When you clone a repository, you also clone all its branches. You may not have
noticed this because Git hides them away: you must ask for them specifically.
This prevents branches in the remote repository from interfering with
your branches, and also makes Git easier for beginners.

List the remote branches with:

 $ git branch -r

You should see something like:

 origin/HEAD
 origin/master
 origin/experimental

These represent branches and the HEAD of the remote repository, and can be used
in regular Git commands. For example, suppose you have made many commits, and
wish to compare against the last fetched version. You could search through the
logs for the appropriate SHA1 hash, but it's much easier to type:

 $ git diff origin/HEAD

Or you can see what the ``experimental'' branch has been up to:

 $ git log origin/experimental

=== Multiple Remotes ===

Suppose two other developers are working on our project, and we want to
keep tabs on both. We can follow more than one repository at a time with:

 $ git remote add other git://example.com/some_repo.git
 $ git pull other some_branch

Now we have merged in a branch from the second repository, and we have
easy access to all branches of all repositories:

 $ git diff origin/experimental^ other/some_branch~5

But what if we just want to compare their changes without affecting our own
work? In other words, we want to examine their branches without having
their changes invade our working directory. Then rather than pull, run:

 $ git fetch        # Fetch from origin, the default.
 $ git fetch other  # Fetch from the second programmer.

This just fetches histories. Although the working directory remains untouched,
we can refer to any branch of any repository in a Git command because we now
possess a local copy.

Recall that behind the scenes, a pull is simply a *fetch* then *merge*.
Usually we *pull* because we want to merge the latest commit after a fetch;
this situation is a notable exception.

See *git help remote* for how to remove remote repositories, ignore certain
branches, and more.

=== My Preferences ===

For my projects, I like contributors to prepare repositories from which I can
pull. Some Git hosting services let you host your own fork of a project with
the click of a button.

After I fetch a tree, I run Git commands to navigate and examine the changes,
which ideally are well-organized and well-described. I merge my own changes,
and perhaps make further edits. Once satisfied, I push to the main repository.

Though I infrequently receive contributions, I believe this approach scales
well. See
http://torvalds-family.blogspot.com/2009/06/happiness-is-warm-scm.html[this
blog post by Linus Torvalds].

Staying in the Git world is slightly more convenient than patch files, as it
saves me from converting them to Git commits. Furthermore, Git handles details
such as recording the author's name and email address, as well as the time and
date, and asks the author to describe their own change.