-
Notifications
You must be signed in to change notification settings - Fork 390
/
index.html
560 lines (551 loc) · 23.2 KB
/
index.html
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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
<title>Explain Git with D3</title>
<script data-main="js/main" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.4/require.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/2.1.0/normalize.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/1140/2.0/1140.css">
<link rel="stylesheet" href="css/explaingit.css">
</head>
<body>
<a href="https://github.com/onlywei/explain-git-with-d3" id="fork-me">
<img style="position: absolute; top: 0; right: 0; border: 0;"
src="https://s3.amazonaws.com/github/ribbons/forkme_right_red_aa0000.png"
alt="Fork me on GitHub">
</a>
<div class="container">
<div class="row intro">
<div class="twelvecol">
<h1>Visualizing Git Concepts with D3</h1>
<p>
This website is designed to help you understand some basic git concepts visually.
This is my first attempt at using both SVG and D3. I hope it is helpful to you.
</p>
<p>
Adding/staging your files for commit will not be covered by this site. In all sandbox playgrounds
on this site, just pretend that you always have files staged and ready to commit at all times.
If you need a refresher on how to add or stage files for commit, please read
<a href="http://git-scm.com/book/en/Git-Basics-Recording-Changes-to-the-Repository">Git Basics</a>.
</p>
<p>
Sandboxes are split by specific git commands, listed below.
</p>
</div>
</div>
<div class="row command-list">
<div class="twocol">
<h4>Basic Commands</h3>
<a id="open-commit" class="openswitch" href="#commit">git commit</a>
<a id="open-branch" class="openswitch" href="#branch">git branch</a>
</div>
<div class="twocol">
<h4> </h4>
<a id="open-checkout" class="openswitch" href="#checkout">git checkout</a>
<a id="open-checkout-b" class="openswitch" href="#checkout-b">git checkout -b</a>
</div>
<div class="twocol">
<h4>Undo Commits</h4>
<a id="open-reset" class="openswitch" href="#reset">git reset</a>
<a id="open-revert" class="openswitch" href="#revert">git revert</a>
</div>
<div class="twocol">
<h4>Combine Branches</h4>
<a id="open-merge" class="openswitch" href="#merge">git merge</a>
<a id="open-rebase" class="openswitch" href="#rebase">git rebase</a>
</div>
<div class="twocol">
<h4>Remote Server</h4>
<a id="open-fetch" class="openswitch" href="#fetch">git fetch</a>
<a id="open-pull" class="openswitch" href="#pull">git pull</a>
</div>
<div class="twocol last">
<h4> </h4>
<a id="open-push" class="openswitch" href="#push">git push</a>
<a id="open-tag" class="openswitch" href="#tag">git tag</a>
</div>
</div>
<div class="row concept-area">
<div id="ExplainGitCommit-Container" class="twelvecol concept-container">
<p>
We are going to skip instructing you on how to add your files for commit in this explanation.
Let's assume you already know how to do that. If you don't, go read some other tutorials.
</p>
<p>
Pretend that you already have your files staged for commit and enter <span class="cmd">git commit</span>
as many times as you like in the terminal box.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitTag-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git tag name</span> will create a new tag named "name".
Creating tags just creates a new tag pointing to the currently checked out commit.
</p>
<p>
Tags can be deleted using the command <span class="cmd">git tag -d name</span> (coming soon).
</p>
<p>
Type <span class="cmd">git commit</span> and <span class="cmd">git tag</span> commands
to your hearts desire until you understand this concept.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitBranch-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git branch name</span> will create a new branch named "name".
Creating branches just creates a new tag pointing to the currently checked out commit.
</p>
<p>
Branches can be deleted using the command <span class="cmd">git branch -d name</span>.
</p>
<p>
Type <span class="cmd">git commit</span> and <span class="cmd">git branch</span> commands
to your hearts desire until you understand this concept.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitCheckout-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git checkout</span> has many uses,
but the main one is to switch between branches.</br>
For example, to switch from master branch to dev branch,
I would type <span class="cmd">git checkout dev</span>.
After that, if I do a git commit, notice where it goes. Try it.
</p>
<p>
In addition to checking out branches, you can also checkout individual commits. Try it.</br>
Make a new commit and then type <span class="cmd">git checkout bb92e0e</span>
and see what happens.
</p>
<p>
Type <span class="cmd">git commit</span>, <span class="cmd">git branch</span>,
and <span class="cmd">git checkout</span> commands to your hearts desire
until you understand this concept.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitCheckout-b-Container" class="twelvecol concept-container">
<p>
You can combine <span class="cmd">git branch</span> and <span class="cmd">git checkout</span>
into a single command by typing <span class="cmd">git checkout -b branchname</span>.
This will create the branch if it does not already exist and immediately check it out.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitReset-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git reset</span> will move HEAD and the current branch back to wherever
you specify, abandoning any commits that may be left behind. This is useful to undo a commit
that you no longer need.
</p>
<p>
This command is normally used with one of three flags: "--soft", "--mixed", and "--hard".
The soft and mixed flags deal with what to do with the work that was inside the commit after
you reset, and you can read about it <a href="https://git-scm.com/book/en/v2/Git-Tools-Reset-Demystified">here</a>.
Since this visualization cannot graphically display that work, only the "--hard" flag will work
on this site.
</p>
<p>
The ref "HEAD^" is usually used together with this command. "HEAD^" means "the commit right
before HEAD. "HEAD^^" means "two commits before HEAD", and so on.
</p>
<p>
Note that you must <b>never</b> use <span class="cmd">git reset</span> to abandon commits
that have already been pushed and merged into the origin. This can cause your local repository
to become out of sync with the origin. Don't do it unless you really know what you're doing.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitRevert-Container" class="twelvecol concept-container">
<p>
To undo commits that have already been pushed and shared with the team, we cannot use the
<span class="cmd">git reset</span> command. Instead, we have to use <span class="cmd">git revert</span>.
</p>
<p>
<span class="cmd">git revert</span> will create a new commit that will undo all of the work that
was done in the commit you want to revert.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitMerge-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git merge</span> will create a new commit with two parents. The resulting
commit snapshot will have the all of the work that has been done in both branches.
</p>
<p>
If there was no divergence between the two commits, git will do a "fast-forward" method merge.</br>
To see this happen, checkout the 'ff' branch and then type <span class="cmd">git merge dev</span>.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitRebase-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git rebase</span> will take the commits on this branch and "move" them so that their
new "base" is at the point you specify.
</p>
<p>
You should pay close attention to the commit IDs of the circles as they move when you do this exercise.
</p>
<p>
The reason I put "move" in quotations because this process actually generates brand new commits with
completely different IDs than the old commits, and leaves the old commits where they were. For this reason,
you never want to rebase commits that have already been shared with the team you are working with.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitFetch-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git fetch</span> will update all of the "remote tracking branches" in your local repository.
Remote tracking branches are tagged in grey.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitPull-Container" class="twelvecol concept-container">
<p>
A <span class="cmd">git pull</span> is a two step process that first does a <span class="cmd">git fetch</span>,
and then does a <span class="cmd">git merge</span> of the remote tracking branch associated with your current branch.
If you have no current branch, the process will stop after fetching.
</p>
<p>
If the argument "--rebase" was given by typing <span class="cmd">git pull --rebase</span>, the second step of
pull process will be a rebase instead of a merge. This can be set to the default behavior by configuration by typing:
<span class="cmd">git config branch.BRANCHNAME.rebase true</span>.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitPush-Container" class="twelvecol concept-container">
<p>
A <span class="cmd">git push</span> will find the commits you have on your local branch that the corresponding branch
on the origin server does not have, and send them to the remote repository.
</p>
<p>
By default, all pushes must cause a fast-forward merge on the remote repository. If there is any divergence between
your local branch and the remote branch, your push will be rejected. In this scenario, you need to pull first and then
you will be able to push again.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitClean-Container" class="twelvecol concept-container">
<p>
One simple example of the use of <span class="cmd">git reset</span> is to completely restore your local repository
state to that of the origin.</br>
You can do so by typing <span class="cmd">git reset origin/master</span>.
</p>
<p>
Note that this won't delete untracked files, you will have to delete those separately with
the command <span class="cmd">git clean -df</span>.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitFetchRebase-Container" class="twelvecol concept-container">
<p>
Below is a situation in which you are working in a local branch that is all your own. You want to receive the latest code
from the origin server's master branch. To update your local branch, you can do it without having to switch branches!
</p>
<p>
First do a <span class="cmd">git fetch</span>, then type <span class="cmd">git rebase origin/master</span>!
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitDeleteBranches-Container" class="twelvecol concept-container">
<p>
<span class="cmd">git branch -d</span> is used to delete branches.
I have pre-created a bunch of branches for you to delete in the playground below.
Have at it.
</p>
<div class="playground-container"></div>
</div>
<div id="ExplainGitFree-Container" class="twelvecol concept-container">
<p>
Do whatever you want in this free playground.
</p>
<div class="playground-container"></div>
</div>
</div>
<div class="row">
<div class="twelvecol">
<h2>Specific Examples</h2>
<p>Below I have created some specific real-world scenarios that I feel are quite common and useful.</p>
</div>
</div>
<div class="row example-list">
<div class="tencol">
<a id="open-clean" class="openswitch" href="#clean">Restore Local Branch to State on Origin Server</a>
<a id="open-fetchrebase" class="openswitch" href="#fetchrebase">Update Private Local Branch with Latest from Origin</a>
<a id="open-deletebranches" class="openswitch" href="#deletebranches">Deleting Local Branches</a>
</div>
<div class="twocol last">
<a id="open-freeplay" class="openswitch" href="#freeplay">Free Playground</a>
<a id="open-zen" class="openswitch" href="#zen">Zen Mode</a>
</div>
</div>
</div>
<div id="ExplainGitZen-Container" style="display:none">
<div class="playground-container"></div>
</div>
<svg version="1.1" baseProfile="full"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:ev="http://www.w3.org/2001/xml-events"
width="0" height="0">
<marker id="triangle" refX="5" refY="5" markerUnits="strokeWidth" fill="#666"
markerWidth="4" markerHeight="3" orient="auto" viewBox="0 0 10 10">
<path d="M 0 0 L 10 5 L 0 10 z"/>
</marker>
<marker id="faded-triangle" refX="5" refY="5" markerUnits="strokeWidth" fill="#DDD"
markerWidth="4" markerHeight="3" orient="auto" viewBox="0 0 10 10">
<path d="M 0 0 L 10 5 L 0 10 z"/>
</marker>
<marker id="brown-triangle" refX="5" refY="5" markerUnits="strokeWidth" fill="#663300"
markerWidth="4" markerHeight="3" orient="auto" viewBox="0 0 10 10">
<path d="M 0 0 L 10 5 L 0 10 z"/>
</marker>
</svg>
<script type="text/javascript">
require(['explaingit'], function (explainGit) {
var examples = {
'commit': {
name: 'Commit',
height: 200,
baseLine: 0.4,
commitData: [
{id: 'e137e9b', tags: ['master']}
],
initialMessage: 'Type git commit a few times.'
},
'branch': {
name: 'Branch',
baseLine: 0.6,
commitData: [
{id: 'e137e9b', tags: ['master']}
]
},
'tag': {
name: 'Tag',
baseLine: 0.6,
commitData: [
{id: 'e137e9b', tags: ['master']}
]
},
'checkout': {
name: 'Checkout',
height: 500,
commitData: [
{id: 'e137e9b'},
{id: 'bb92e0e', parent: 'e137e9b', tags: ['master']},
{id: 'e088135', parent: 'e137e9b', tags: ['dev']}
],
initialMessage:
'Use git checkout, git branch, and git commit commands until you understand.'
},
'checkout-b': {
name: 'Checkout-b',
height: 500,
commitData: [
{id: 'e137e9b'},
{id: 'f5b32c8', parent: 'e137e9b'},
{id: 'bb92e0e', parent: 'f5b32c8', tags: ['master']},
{id: 'e088135', parent: 'e137e9b', tags: ['dev']}
],
initialMessage:
'Use git checkout -b and git commit commands until you understand.'
},
'reset': {
name: 'Reset',
height: 200,
baseLine: 0.5,
commitData: [
{id: 'e137e9b'},
{id: '0e70093', parent: 'e137e9b'},
{id: '3e33afd', parent: '0e70093', tags: ['master']}
],
initialMessage: 'Type "git reset HEAD^".'
},
'revert': {
name: 'Revert',
height: 200,
baseLine: 0.5,
commitData: [
{id: 'e137e9b'},
{id: '0e70093', parent: 'e137e9b'},
{id: '3e33afd', parent: '0e70093', tags: ['master']}
],
initialMessage: 'Type "git revert 0e70093".'
},
'merge': {
name: 'Merge',
height: 500,
commitData: [
{id: 'e137e9b'},
{id: 'bb92e0e', parent: 'e137e9b', tags: ['master']},
{id: 'f5b32c8', parent: 'e137e9b', tags: ['ff']},
{id: 'e088135', parent: 'f5b32c8', tags: ['dev']}
],
initialMessage:
'Type "git merge dev".'
},
'rebase': {
name: 'Rebase',
height: 500,
commitData: [
{id: 'e137e9b'},
{id: 'bb92e0e', parent: 'e137e9b', tags: ['master']},
{id: 'f5b32c8', parent: 'e137e9b'},
{id: 'e088135', parent: 'f5b32c8', tags: ['dev']}
],
currentBranch: 'dev',
initialMessage:
'Type "git rebase master".'
},
'fetch': {
name: 'Fetch',
height: 500,
commitData: [
{id: 'e137e9b', tags: ['origin/master']},
{id: '6ce726f', parent: 'e137e9b'},
{id: 'bb92e0e', parent: '6ce726f', tags: ['master']},
{id: '0cff760', parent: 'e137e9b', tags: ['origin/dev']},
{id: '4ed301d', parent: '0cff760', tags: ['dev']}
],
originData: [
{id: 'e137e9b'},
{id: '7eb7654', parent: 'e137e9b'},
{id: '090e2b8', parent: '7eb7654'},
{id: 'ee5df4b', parent: '090e2b8', tags: ['master']},
{id: '0cff760', parent: 'e137e9b'},
{id: '2f8d946', parent: '0cff760'},
{id: '29235ca', parent: '2f8d946', tags: ['dev']}
],
initialMessage:
'Carefully compare the commit IDs between the origin and the local repository. ' +
'Then type "git fetch".'
},
'pull': {
name: 'Pull',
height: 500,
commitData: [
{id: 'e137e9b', tags: ['origin/master']},
{id: '46d095b', parent: 'e137e9b', tags: ['master']}
],
originData: [
{id: 'e137e9b'},
{id: '7eb7654', parent: 'e137e9b'},
{id: '090e2b8', parent: '7eb7654'},
{id: 'ee5df4b', parent: '090e2b8', tags: ['master']}
],
initialMessage:
'Carefully compare the commit IDs between the origin and the local repository. ' +
'Then type "git pull".'
},
'push': {
name: 'Push',
height: 500,
commitData: [
{id: 'e137e9b', tags: ['origin/master']},
{id: '46d095b', parent: 'e137e9b', tags: ['master']}
],
originData: [
{id: 'e137e9b'},
{id: '7eb7654', parent: 'e137e9b', tags: ['master']}
],
initialMessage:
'Carefully compare the commit IDs between the origin and the local repository. ' +
'Then type "git push".'
},
'clean': {
name: 'Clean',
height: 200,
baseLine: 0.4,
commitData: [
{id: 'e137e9b', tags: ['origin/master']},
{id: '0e70093', parent: 'e137e9b'},
{id: '3e33afd', parent: '0e70093', tags: ['master']}
],
initialMessage: 'Type "git reset origin/master".'
},
'fetchrebase': {
name: 'FetchRebase',
height: 500,
commitData: [
{id: 'e137e9b', tags: ['origin/master', 'master']},
{id: '46d095b', parent: 'e137e9b'},
{id: 'dccdc4d', parent: '46d095b', tags: ['my-branch']}
],
currentBranch: 'my-branch',
originData: [
{id: 'e137e9b'},
{id: '7eb7654', parent: 'e137e9b'},
{id: '090e2b8', parent: '7eb7654'},
{id: 'ee5df4b', parent: '090e2b8', tags: ['master']}
],
initialMessage:
'First type "git fetch". Then type "git rebase origin/master".'
},
'deletebranches': {
name: 'DeleteBranches',
height: 500,
baseLine: 0.6,
commitData: [
{id: 'e137e9b'},
{id: 'bb92e0e', parent: 'e137e9b'},
{id: 'd25ee9b', parent: 'bb92e0e', tags: ['master']},
{id: '071ff28', parent: 'e137e9b', tags: ['protoss']},
{id: 'f5b32c8', parent: 'bb92e0e'},
{id: 'e088135', parent: 'f5b32c8', tags: ['zerg']},
{id: '9e6c322', parent: 'bb92e0e'},
{id: '593ae02', parent: '9e6c322', tags: ['terran']}
],
currentBranch: 'terran',
initialMessage:
'Delete some branches.'
},
'freeplay': {
name: 'Free',
height: 500,
commitData: [
{id: 'e137e9b', tags: ['origin/master', 'master']}
],
originData: [
{id: 'e137e9b'},
{id: '7eb7654', parent: 'e137e9b'},
{id: '090e2b8', parent: '7eb7654'},
{id: 'ee5df4b', parent: '090e2b8', tags: ['master']}
],
initialMessage:
'Have fun.'
}
};
window.addEventListener('hashchange', open, false);
window.addEventListener('load', open, false);
function open() {
var hash = window.location.hash.substr(1),
linkId = 'open-' + hash,
example = examples[hash];
if (example) {
explainGit.reset();
document.getElementById(linkId).classList.add('selected');
explainGit.open(example);
} else if (hash === 'zen') {
var elements = document.getElementsByClassName('row');
for(var i = 0; i != elements.length; ++i)
{
elements[i].style.display = 'none';
}
document.getElementById('fork-me').style.display = 'none';
explainGit.reset();
explainGit.open({
name: 'Zen',
height: '100%',
commitData: [
{id: 'e137e9b', tags: ['master'], message: 'first commit'}
],
initialMessage:
'Have fun.'
});
}
}
});
</script>
</body>
</html>