-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgit-github.qmd
496 lines (357 loc) · 22.3 KB
/
git-github.qmd
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
---
editor:
markdown:
wrap: sentence
---
# GitHub 원격 작업 {#git-github}
\index{git!GitHub} \index{원격 작업}
버전 제어(version control)는 다른 사람과 협업할 때 진정으로 그 가치를 발휘한다.
우리는 이미 버전 제어를 위해 필요한 대부분의 작업을 수행했다.
한 가지 빠진 것은 한 저장소에서 다른 저장소로 변경 사항을 복사하는 것이다.
Git 같은 시스템은 임의 두 저장소 사이에 작업 내용을 옮길 수 있는 기능을 제공한다.
하지만 실무에서는 다른 사람의 노트북이나 PC보다는 중앙 허브에 웹 방식으로 하나의 원본을 두고 사용하는 것이 가장 쉽다.\
대부분의 프로그래머는 프로그램 마스터 원본을 [GitHub](http://github.com), [BitBucket](http://bitbucket.org), [GitLab](http://gitlab.com/) 호스팅 서비스에 두고 사용한다.
이번 장 마지막 부분에서 이러한 접근법의 장점과 단점을 살펴본다.
\index{GitHub} \index{BitBucket} \index{GitLab}
## 원격 저장소 생성
\index{원격 저장소}
세상 사람들과 현재 프로젝트에서 변경한 사항을 공유하는 것에서부터 시작해보자.
GitHub에 로그인하고 나서, 우측 상단 아이콘을 클릭해서 `planets` 이름으로 신규 저장소를 생성한다.
![(1단계) GitHub 저장소 생성](images/git/github-create-repo-01.png){#fig-github-repo fig-align="center" width="500"}
저장소 이름을 "planets"으로 만들고 "Create Repository"를 클릭한다.
![(2단계) GitHub 저장소 생성](images/git/github-create-repo-02.png){#fig-github-repo-create fig-align="center" width="500"}
저장소가 생성되자마자, GitHub는 URL을 가진 페이지와 로컬 저장소 환경 설정 방법에 대한 정보를 화면에 출력한다.
![(3단계) GitHub 저장소 생성](images/git/github-create-repo-03.png){#fig-github-repo-info fig-align="center" width="500"}
다음 명령어가 실제로 GitHub 서버에서 자동으로 수행된다.
``` bash
$ mkdir planets
$ cd planets
$ git init
```
`mars.txt` 파일을 추가하고 커밋한 이전 [장](#git-change)을 상기한다면, 로컬 저장소는 다음과 같이 도식적으로 표현할 수 있다.
![Git 준비영역(Staging) 로컬 저장소](images/git/git-staging-area.svg){#fig-github-staging fig-align="center" width="428"}
이제 저장소가 두 개로 늘어서, 도식적으로 표현하면 다음과 같다.
![신선한 신규 GitHub 저장소](images/git/git-freshly-made-github-repo.svg){#fig-github-two-repo fig-align="center" width="366"}
현재 로컬 저장소는 여전히 `mars.txt` 파일에 대한 이전 작업 정보를 담고 있다.
하지만 GitHub의 원격 저장소에는 아직 어떠한 파일도 담고 있지 않다.
## 로컬 저장소를 원격 저장소 연결
\index{git!원격 저장소} \index{git!remote} 다음 단계는 두 저장소를 연결하는 것이다.
로컬 저장소를 위해서 GitHub 저장소를 **원격(remote)**으로 만들어 두 저장소를 연결한다.
GitHub의 저장소 홈페이지에 식별하는 데 필요한 문자열이 포함되어 있다.
![GitHub 저장소 URL 발견장소](images/git/github-find-repo-string.png)
HTTPS에서 SSH로 **프로토콜(protocol)**을 변경하려면 'SSH' 링크를 클릭한다.
브라우저에서 해당 URL을 복사한 후, 로컬 `planets` 저장소로 이동하여 아래 명령어를 실행한다.
``` bash
$ git remote add origin git@github.com:vlad/planets.git
```
단, `Vlad`의 저장소 URL이 아닌 여러분의 저장소 URL을 사용해야 한다.
유일한 차이점은 `vlad` 대신 사용자 이름을 사용해야 한다는 것이다.
`origin`이라는 이름은 원격 저장소에 대한 로컬 별명이다.
원한다면 다른 명칭을 사용할 수도 있지만, `origin`이 가장 일반적인 선택이다.
`git remote -v` 명령어를 실행해서 명령어가 제대로 작동했는지 확인한다.
``` bash
$ git remote -v
origin git@github.com:vlad/planets.git (fetch)
origin git@github.com:vlad/planets.git (push)
```
::: callout-tip
### HTTPS vs. SSH
\index{SSH} \index{HTTPS}
여기서 SSH를 사용하는데, 이는 추가적인 설정이 필요하지만 많은 애플리케이션에서 널리 사용되는 보안 프로토콜이기 때문이다.
아래 단계는 GitHub를 위한 최소한의 수준에서 SSH를 설명하고 있다.
:::
![GitHub 저장소 URL 변경](images/git/github-change-repo-string.png)
## SSH 배경과 환경설정
드라큘라가 원격 저장소에 연결하기 전에, 컴퓨터가 GitHub와 인증할 수 있는 방법을 설정해야 한다.
이를 통해 GitHub은 원격 저장소에 연결하려는 사람이 바로 드라큘라 본인임을 알 수 있다.
많은 다양한 서비스에서 명령줄(command line)에 대한 접근을 인증하기 위해 일반적으로 사용되는 방법을 설정할 것이다.
방법을 **보안 쉘 프로토콜(Secure Shell Protocol, SSH)**이라고 한다.
SSH는 보안이 안전하지 않은 네트워크에서도 컴퓨터 간에 안전한 통신을 가능하게 하는 암호화 네트워크 프로토콜이다.
SSH는 **키 쌍(key pair)**이라는 것을 사용한다.
접근을 검증하기 위해 함께 작동하는 두 개의 키이다.
하나의 키는 공개적으로 알려져 있으며 **공개 키(public key)**라고 하고, 다른 키는 **비밀 키(private key)**라고 하며 비공개로 유지된다.
명칭 자체가 매우 직관적이다.
\index{공개 키} \index{비밀 키}
공개 키는 자물쇠로, 본인만이 자물쇠를 열 수 있는 키(비밀 키)를 가지고 있다고 생각할 수 있다.
GitHub 계정과 같이 안전한 통신 방법이 필요한 곳에 공개 키를 사용한다.
이 자물쇠, 즉 공개 키를 GitHub에 제공하고 "내 계정에 대한 통신을 이 키로 잠그세요. 그러면 내 비밀 키를 가진 컴퓨터만이 통신을 잠금 해제하고 내 GitHub 계정으로 `git` 명령을 보낼 수 있습니다."라고 말한다.
지금 할 일은 SSH 키를 설정하고 공개 키를 GitHub 계정에 추가하는 데 필요한 최소한의 작업이다.
가장 먼저 할 일은 현재 사용 중인 컴퓨터에서 해당 작업이 이미 완료되었는지 확인하는 것이다.
일반적으로 이러한 설정은 한 번만 이루어지면 되고, 이후에는 신경 쓸 필요가 없기 때문이다.
::: callout-tip
### 키 안전하게 보관하기
SSH 키는 계정을 안전하게 유지하기 때문에 실제로 잊어서는 안 된다.
특히 여러 컴퓨터에서 계정에 접속하는 경우라면 가끔씩 **보안 쉘 키**를 점검하는 것이 좋은 습관이다.
:::
컴퓨터에 이미 존재하는 키 쌍을 확인하기 위해 `ls` 명령어를 실행한다.
``` bash
ls -al ~/.ssh
```
출력 결과는 사용자별로 사용 중인 컴퓨터에 SSH가 설정되어 있는지 여부에 따라 약간 달라진다.
드라큘라는 컴퓨터에 SSH를 설정한 적이 전혀 없으므로, 출력 결과는 다음과 같다.
``` bash
ls: cannot access '/c/Users/Vlad Dracula/.ssh': No such file or directory
```
만약 사용 중인 컴퓨터에 SSH가 설정되어 있다면, 공개 키와 비밀 키 쌍이 나열될 것이다.
파일 이름은 키 쌍이 설정된 방식에 따라 `id_ed25519/id_ed25519.pub` 또는 `id_rsa/id_rsa.pub` 중 하나다.
드라큘라 컴퓨터에는 이러한 키 쌍이 존재하지 않으므로, 다음 명령어를 사용하여 키 쌍을 생성한다.
### SSH 키 쌍 생성
SSH 키 쌍을 생성하기 위해 드라큘라는 다음 명령어를 사용하는데, 여기서 `-t` 옵션은 사용할 알고리즘 유형을 지정하고 `-C`는 키에 주석(여기서는 드라큘라의 이메일)을 첨부한다.
``` bash
$ ssh-keygen -t ed25519 -C "vlad@tran.sylvan.ia"
```
만약 Ed25519 알고리즘을 지원하지 않는 레거시 시스템을 사용 중이라면, 다음 명령어(`ssh-keygen -t rsa -b 4096 -C "your_email@example.com"`)를 사용한다.
``` bash
Generating public/private ed25519 key pair.
Enter file in which to save the key (/c/Users/Vlad Dracula/.ssh/id_ed25519):
```
기본 파일을 사용하고 싶으므로, 그냥 <kbd>Enter</kbd> 키를 누른다.
``` bash
Created directory '/c/Users/Vlad Dracula/.ssh'.
Enter passphrase (empty for no passphrase):
```
이제 드라큘라에게 **암호 문구(Passphrase)**[^git-github-1]를 입력하라고 요청한다.
다른 사람들이 가끔 접근할 수 있는 연구실 노트북을 사용하고 있기 때문에, 암호 문구를 생성하고 싶어 한다.
"비밀번호 재설정" 옵션이 없으므로 기억하기 쉬운 것을 사용하거나 암호 문구를 어딘가에 저장해 두어야 한다.
[^git-github-1]: 암호 문구는 암호(Password)와 비슷하지만 띄어쓰기를 포함한 더 긴 문장이나 구절을 사용한다는 점이 다르다.
예를 들어, "I love coding with ChatGPT!"와 같이 여러 단어로 이루어진 문장을 Passphrase로 사용할 수 있다.
암호 문구가 암호보다 길기 때문에 보안성이 더 높다고 여겨진다.
추측하거나 무작위로 대입하기가 더 어렵기 때문으로 IT 분야에서 암호 대신 Passphrase를 사용하는 것이 점점 더 일반화되고 있는 추세다.
``` bash
Enter same passphrase again:
```
동일한 패스프레이즈를 한 번 더 입력한 후, 확인 메시지를 받는다.
``` bash
Your identification has been saved in /c/Users/Vlad Dracula/.ssh/id_ed25519
Your public key has been saved in /c/Users/Vlad Dracula/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:SMSPIStNyA00KPxuYu94KpZgRAYjgt9g4BA4kFy3g1o vlad@tran.sylvan.ia
The key's randomart image is:
+--[ED25519 256]--+
|^B== o. |
|%*=.*.+ |
|+=.E =.+ |
| .=.+.o.. |
|.... . S |
|.+ o |
|+ = |
|.o.o |
|oo+. |
+----[SHA256]-----+
```
"identification"은 실제로 비밀 키이다.
비밀 키를 절대 공유해서는 안 된다.
공개 키는 적절하게 명명되었다.
"key fingerprint"는 공개 키의 짧은 버전이다.
이제 SSH 키를 생성했으므로, 확인해 보면 SSH 파일들을 찾을 수 있다.
``` bash
$ ls -al ~/.ssh
drwxr-xr-x 1 Vlad Dracula 197121 0 Jul 16 14:48 ./
drwxr-xr-x 1 Vlad Dracula 197121 0 Jul 16 14:48 ../
-rw-r--r-- 1 Vlad Dracula 197121 419 Jul 16 14:48 id_ed25519
-rw-r--r-- 1 Vlad Dracula 197121 106 Jul 16 14:48 id_ed25519.pub
```
### 공개 키를 GitHub에 복사
이제 SSH 키 쌍을 가지고 있고, GitHub 인증여부를 확인하기 위해 다음 명령어를 실행할 수 있다.
``` bash
$ ssh -T git@github.com
The authenticity of host 'github.com (192.30.255.112)' can't be established.
RSA key fingerprint is SHA256:nThbg6kXUpJWGl7E1IGOCspRomTxdCARLviKw6E5SY8.
This key is not known by any other names
Are you sure you want to continue connecting (yes/no/[fingerprint])? y
Please type 'yes', 'no' or the fingerprint: yes
Warning: Permanently added 'github.com' (RSA) to the list of known hosts.
git@github.com: Permission denied (publickey).
```
맞다.
GitHub에 공개 키를 제공해야 한다는 것을 잊었다!
먼저, 공개 키를 복사해야 한다.
그렇지 않으면 비밀 키와 혼동을 일으킬 수 있기 때문에 `.pub` 확장자를 반드시 포함해야 한다.
``` bash
$ cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDmRA3d51X0uu9wXek559gfn6UFNF69yZjChyBIU2qKI vlad@tran.sylvan.ia
```
이제 \<GitHub.com\>에 접속하여, 오른쪽 상단 모서리에 있는 프로필 아이콘을 클릭하여 드롭다운 메뉴를 연다.
"Settings"를 클릭하고, 설정 페이지에서 왼쪽의 "Account settings" 메뉴에서 "SSH and GPG keys"를 클릭한다.
오른쪽의 "New SSH key" 버튼을 클릭한다.
이제 제목을 추가할 수 있다(드라큘라는 원래 키 쌍 파일이 어디에 있는지 기억할 수 있도록 "Vlad's Lab Laptop"이라는 제목을 사용한다).
SSH 키를 필드에 붙여넣고 "Add SSH key"를 클릭하여 설정을 완료한다.
이제 설정이 완료되었으니, 명령줄에서 인증을 다시 확인해 보자.
``` bash
$ ssh -T git@github.com
Hi Vlad! You've successfully authenticated, but GitHub does not provide shell access.
```
좋다!
출력결과는 SSH 키가 의도한 대로 작동함을 확인해 준다.
이제 작업 내용을 원격 저장소에 푸시할 준비가 되었다.
## 로컬 변경사항 원격 저장소 푸시
이제 인증 설정이 완료되었으므로, 원격 저장소로 돌아갈 수 있다.
다음 명령어는 로컬 저장소에서의 변경 사항을 GitHub 저장소로 푸시한다.
``` bash
$ git push origin main
```
드라큘라가 암호 문구(passphrase)를 설정했기 때문에, 명령어 실행 시 암호 문구를 입력하라는 프롬프트가 표시된다.
만약 인증에 대한 고급 설정을 완료했다면, 암호 문구를 요구하지 않을 것이다.
``` bash
Enumerating objects: 16, done.
Counting objects: 100% (16/16), done.
Delta compression using up to 8 threads.
Compressing objects: 100% (11/11), done.
Writing objects: 100% (16/16), 1.45 KiB | 372.00 KiB/s, done.
Total 16 (delta 2), reused 0 (delta 0)
remote: Resolving deltas: 100% (2/2), done.
To https://github.com/vlad/planets.git
* [new branch] main -> main
```
::: callout-tip
### 프록시(Proxy)
만약 연결된 네트워크가 프록시를 사용한다면, "Could not resolve hostname" 오류 메시지로 인해서 마지막 명령어가 실패할 가능성이 있다.
이 문제를 해결하기 위해서는 프록시에 대한 정보를 Git에 전달할 필요가 있다.
``` bash
$ git config --global http.proxy http://user:password@proxy.url
$ git config --global https.proxy http://user:password@proxy.url
```
프록시를 사용하지 않는 또 다른 네트워크에 연결될 때는 Git에게 프록시 기능을 사용하지 않도록 다음 명령어를 사용하여 알려준다.
``` bash
$ git config --global --unset http.proxy
$ git config --global --unset https.proxy
```
:::
::: callout-tip
### 비밀번호 관리자
운영체제에 **비밀번호 관리자(password manager)**가 설정되어 있다면, 사용자이름(username)과 비밀번호(password)가 필요할 때, `git push` 명령어가 이를 사용하려 한다.
"Git Bash on Windows"를 사용하면 기본 디폴트 행동이다.
관리자 비밀번호를 사용하는 대신에, 터미널에서 사용자이름과 비밀번호를 입력하려면, `git push`를 실행하기 전에 터미널에서 다음과 같이 타이핑한다.
``` bash
$ unset SSH_ASKPASS
```
[git uses `SSH_ASKPASS` for all credential entry](https://git-scm.com/docs/gitcredentials#_requesting_credentials)에도 불구하고, SSH나 HTTPS를 경유하여 Git을 사용하든 `SSH_ASKPASS`를 설정하고 싶지 않을 수도 있다.
`~/.bashrc` 파일 하단에 `unset SSH_ASKPASS`를 추가해서 Git으로 하여금 사용자명과 비밀번호를 사용하도록 기본설정으로 둘 수도 있다.
:::
이제 로컬 저장소와 원격 저장소는 다음과 같은 상태가 된다.
\index{git!push} \index{푸시} \index{원격 저장소}
![첫 번째 푸시(Push) 다음 GitHub 저장소](images/git/github-repo-after-first-push.svg){#fig-github-repo-push fig-align="center" width="539"}
::: callout-tip
### '-u' 플래그(flag)
Git 문서에서 `git push`와 함께 사용되는 `-u` 옵션을 볼 수 있다.
`git branch` 명령어에 대한 `--set-upstream-to` 옵션과 동의어에 해당되는 옵션이다.
원격 브랜치를 현재 브랜치와 연결시키는 데 사용된다.
그래서 `git pull` 명령어가 아무런 인자 없이 사용될 수 있다.
원격 저장소가 설정되면, `git push -u origin master` 명령어만 실행시키면 연결 작업이 완료된다.
:::
또한, 원격 저장소에서 로컬 저장소로 변경 사항을 풀(pull)해서 가져올 수도 있다.
``` bash
$ git pull origin main
From https://github.com/vlad/planets
* branch master -> FETCH_HEAD
Already up-to-date.
```
이 경우 가져오기 하는 풀(`pull`)은 아무런 결과가 없는데, 이유는 두 저장소가 이미 동기화되어 있기 때문이다.
하지만 만약 누군가 GitHub 저장소에 변경 사항을 푸시했다면, 상기 명령어는 변경된 사항을 로컬 저장소로 다운로드한다.
::: callout-tip
### GitHub 브라우저에서 직접 파일 업로드
GitHub에서는 명령줄(command line)을 거치지 않고 브라우저를 떠나지 않은 채로 파일을 직접 저장소에 업로드할 수 있는 기능도 제공한다.
두 가지 방법이 있다.
첫째는 파일 트리 상단의 툴바에 있는 "Upload files" 버튼을 클릭하는 것이고, 둘째는 데스크톱에서 파일을 파일 트리로 드래그 앤 드롭하는 것이다.
이에 대한 자세한 내용은 [GitHub 페이지](https://help.github.com/articles/adding-a-file-to-a-repository/)에서 확인할 수 있다.
:::
::: callout-tip
### GitHub GUI
\index{GitHub!GUI}
GitHub 웹사이트에서 `planets` 저장소를 찾아간다.
`Code` 탭 아래 "XX commits"("XX"는 숫자) 텍스트를 클릭한다.
각 커밋 우측의 버튼 세 개를 여기저기 둘러보고, 클릭해 본다.
버튼을 눌러서 어떤 정보를 모을 수 있거나 탐색할 수 있는가?
쉘에서 동일한 정보를 어떻게 얻을 수 있을까?
::: {.callout-caution collapse="true"}
### 해답
(클립보드 그림을 갖는) 가장 좌측 버튼은 클립보드에 커밋 식별자 전체를 복사한다.
쉘에서 `git log` 명령어가 각 커밋에 대한 전체 커밋 식별자를 보여준다.
중간 버튼을 클릭하게 되면, 특정 커밋으로 변경한 내용 전체를 확인할 수 있다.
녹색 음영선은 추가를 붉은색 음영선은 삭제를 의미한다.
쉘에서 동일한 작업을 `git diff`로 할 수 있다.
특히, `git diff ID1..ID2`(ID1와 ID2는 커밋 식별자다) 명령어(즉, `git diff a3bf1e5..041e637`)는 두 커밋 사이 차이를 보여준다.
가장 우측 버튼은 커밋 당시에 저장소의 모든 파일을 보여준다.
쉘로 이런 작업을 수행하려면, 해당 시점의 저장소를 checkout 해야 한다.
쉘에서 `git checkout ID`(여기서 ID는 살펴보려고 하는 커밋 식별자) 명령어를 실행하면 된다.
checkout 하게 되면, 나중에 저장소를 올바른 상태로 되돌려 놓아야 된다는 것을 기억해야 한다.
:::
:::
::: callout-tip
### GitHub 시간도장
\index{GitHub!시간도장}
GitHub에 원격 저장소를 생성한다.
로컬 저장소의 콘텐츠를 원격 저장소로 푸시한다.
로컬 저장소에 변경 사항을 만들고, 변경 사항을 푸시한다.
방금 생성한 GitHub 저장소로 가서 GitHub 변경 사항에 대한 **시간도장(timestamps)**을 살펴본다.
GitHub이 시간 정보를 어떻게 기록하는가?
왜 그런가?
::: {.callout-caution collapse="true"}
### 해답
GitHub은 시간도장을 사람이 읽기 쉬운 형태로 표시한다(즉, "22 hours ago" 혹은 "three weeks ago").
하지만 시간도장을 이리저리 살펴보면, 파일의 마지막 변경이 발생된 정확한 시간을 볼 수 있다.
:::
:::
::: callout-tip
### 푸시(Push) vs. 커밋(Commit)
\index{git!push} \index{git!commit}
이번 장에서, "git push" 명령어를 소개했다.
"git push" 명령어가 "git commit" 명령어와 어떻게 다른가?
::: {.callout-caution collapse="true"}
### 해답
변경 사항을 푸시하면, 로컬에서 변경한 사항을 원격 저장소와 상호 협의하여 최신 상태로 갱신한다.
(흔히 다른 사람이 변경시킨 것을 공유하는 것도 이에 해당된다.) 커밋은 로컬 저장소만 갱신한다는 점에서 차이가 난다.
:::
:::
::::: callout-tip
### 원격 설정 고치기
원격 URL에 오탈자가 발생되는 일이 실무에서 흔히 발생한다.
이번 연습문제는 이런 유형의 이슈를 어떻게 고칠 수 있는지에 대한 것이다.
먼저 잘못된 URL을 원격(remote)에 추가하면서 시작해 보자.
``` bash
git remote add broken https://github.com/this/url/is/invalid
```
`git remote`로 추가할 때 오류를 받았나요?
원격 URL이 적법한지 확인해 주는 명령어를 생각해 낼 수 있나요?
URL을 어떻게 수정할 수 있을까요?
(팁: `git remote -h`를 사용한다.) 이번 연습문제를 수행한 다음에 원격(remote)을 지워버리는 것을 잊지 말자.
::: {.callout-caution collapse="true"}
### 해답
원격(remote)를 추가할 때 어떤 오류 메시지도 볼 수 없다.
(원격 remote를 추가하는 것은 Git에게 알려주기만 할 뿐 아직 사용하지는 않았기 때문이다.)\
`git push` 명령어를 사용하자마자, 오류 메시지를 보게 된다.
`git remote set-url` 명령어를 통해서 잘못된 원격 URL을 바꿔 문제를 해결하게 된다.
:::
:::::
::: callout-tip
### GitHub 라이선스와 README 파일
이번 장에서 GitHub에 원격 저장소를 생성하는 방법을 배웠다.
하지만 GitHub 저장소를 초기화할 때 `README.md` 혹은 라이선스 파일을 추가하지 않았다.
로컬 저장소와 원격 저장소를 연결시킬 때 두 파일을 갖게 되면 무슨 일이 발생될 것으로 생각하는가?
::: {.callout-caution collapse="true"}
### 해답
\index{git!pull}
이런 경우, 관련없는 이력 때문에 병합 충돌(merge conflict)이 발생한다.
GitHub에서 `README.md` 파일을 생성시키고 원격 저장소에서 커밋 작업을 수행한다.
로컬 저장소로 원격 저장소를 풀(pull)로 땡겨오면, Git이 `origin`과 공유되지 않는 이력을 탐지하고 병합(merge)을 거부해 버린다.
``` bash
$ git pull origin master
From https://github.com/vlad/planets
* branch master -> FETCH_HEAD
* [new branch] master -> origin/master
fatal: refusing to merge unrelated histories
```
`--allow-unrelated-histories` 옵션으로 두 저장소를 강제로 병합(merge)시킬 수 있다.
이런 옵션을 사용할 때는 주의해야 한다.
병합하기 전에 로컬 저장소와 원격 저장소의 콘텐츠를 면밀히 조사해야 한다.
``` bash
$ git pull --allow-unrelated-histories origin master
From https://github.com/vlad/planets
* branch master -> FETCH_HEAD
Merge made by the 'recursive' strategy.
README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README.md
```
:::
:::