forked from CRIStAL-PADR/reproducible-research-SE-notes
-
Notifications
You must be signed in to change notification settings - Fork 1
/
git_basics.pillar
337 lines (257 loc) · 15.6 KB
/
git_basics.pillar
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
!! Getting Started with Git
In this chapter we introduce the basics of Git and VCSs through guided examples.
We first start by setting up a repository in a remote server and then load it in our own machine.
We then show how we can inspect the state of our repository and save our files into it.
Once our changes are saved, we show how we can push our changes to our remote repository in a distant server.
This chapter will assume you have Git already installed in your machine, and that you're using a *nix operating system.
For users of other systems such as Windows, an appendix at the end will give some details on different setups and installation procedures.
Moreover, you will see that we will approach Git with the ''command-line''.
Don't be affraid if you've never used it before, it is not as difficult as it may seem and you will get used to it.
There is always a first time!
Also, we promise you that everything you learn in here can be applied to, and will actually help you better understand, non command-line tools.
!!! Creating a Repository
A Git repository is a store where we will save changes.
Changes are saved incrementally and all our history of changes in maintained in it.
To create a repository, the easiest way is to create it in an online hosting service such as GitHub or GitLab.
Once you have an account and log into it, get yourself to the ''New Repository'' action, within the menu using the ==+== symbol.
Figure *@new_repo_github* shows the kind of form GitHub provides to its users to create a new repository.
+Creating a New Repository in Github>figures/new-repository-github.png|label=new_repo_github+
Follow the form and create your repository.
Once finished, your repository is created, you'll be redirected to your repository page.
Figure *@repository_page* shows how such a page looks in GitHub.
+A Repository Page for a project called ""test"" in GitHub>figures/GitHub_repository_page.png|label=repository_page+
We are already set to work from the command line now.
!!! ==git clone==
@cloning
Git, constrastingly to other VCSs, is a distributed VCS.
This means that you work not only against the remote repository but also you can work locally.
To support that, Git makes a ""local copy"" of the repository in your machine.
To create such a copy, the easiest way is to use the ==git clone [url]== command.
Git support different kind of urls, the most known being SSH and HTTPS urls.
We will use in this chapter HTTPS urls because they have an easier setup, but for those readers that are curious, Section *@sshvshttps* compares SSH and HTTPS and Section *@setupssh* shows how to setup your SSH environment.
To obtain the HTTPS url of your repository, go to your repository's page and look for it under the clone/HTTPS options.
As an example, Figure *@HTTPS_GitHub* illustrates how to get such url from a GitHub project page.
Copy that url and use it in your command line as first argument of your ==git clone== as in:
+Getting the HTTPS url of your repository from GitHub>figures/HTTPS_url_GitHub.png|width=90|label=HTTPS_GitHub+
[[[language=bash
$ git clone [url]
Cloning into '[your_project_name]'...
remote: Counting objects: 11082, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 11082 (delta 2), reused 6 (delta 2), pack-reused 11076
Receiving objects: 100% (11082/11082), 4.35 MiB | 1.22 MiB/s, done.
Resolving deltas: 100% (4063/4063), done.
Checking connectivity... done.
]]]
When this command finishes, we see it created a directory named as your repository (your_repo_name).
This directory, also called the ""working directory"", is where we will work and interact with our repository.
In other words, all files in this directory are the files that are managed by (and thus stored on) the repository.
Moreover, it is inside this directory that you will issue your Git commands to work.
You are now ready to go and start working on your project.
!!! ==git status==
After some time working, we end up with a couple of new files with some contents on it: ''e.g.,'' a README.md file with some explanations and a txt file with some project information in it.
We can check our advance using the command line commands ==ls== that lists existing files and ==cat== that outputs the contents of the file to the terminal.
[[[language=bash
$ ls
project.txt README.md
]]]
[[[
$ cat project.txt
# Done
- created the repository
- git clone
- created this file
# To do
- commit this file
- push it to my remote repository
]]]
[[[language=bash
$ cat README.md
#My Project
This project is an example Git repository used to learn Git.
Check the project.txt file for information about pending tasks.
]]]
There is something else we can know at this stage: What does Git know about these files?
Git indeed tracks our files to know what should be saved and what should not.
We can use this information to see what are actually the changes that happened while we were working.
To obtain such information from Git, we should use the ==git status== command:
[[[language=bash
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: README.md
Untracked files:
(use "git add <file>..." to include in what will be committed)
project.txt
no changes added to commit (use "git add" and/or "git commit -a")
]]]
Git tells us that the file ==README.md== is modified and that it does not yet know ==project.txt==, it is untracked.
It also tells us that no changes were added to commit and that we need to do a ==git add== to track them.
!!! ==git commit==
We would like now to save our changes in our Git repository.
This way, if anything happens, we can always recover our work up to this point.
Saving our work in the repository is called a ""commit"".
However, before committing our changes, we need to make Git ""track"" them.
To make it simple, you can see this whole tracking story as going to the supermarket.
If you want to buy something from the supermarket, you have take whatever you want first and put it in your basket.
Then, you go to the cashier, you pay and take your things home.
Now imagine that passing through the cashier to pay is equivalent to do a commit command.
This means that first you need to add stuff to your c!
Tracking changes for commit (''i.e.,'' adding stuff to your bag) is done through the ==git add [file]== command.
Let's proceed to track those changes and see what is the status of our repository afterwards.
[[[language=bash
$ git add README.md
$ git add project.txt
$ git status
On branch master
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: README.md
new file: project.txt
]]]
Now Git says that our two new files will be committed.
Let's now proceed to commit to save our changes in the repository.
We can do that by using the ==git commit -m \"[message]\"== command:
[[[language=bash
$ git commit -m "first version"
[master a93c016] first version
2 files changed, 12 insertions(+), 1 deletion(-)
create mode 100644 project.txt
]]]
If we see the status of our repository after the commit we will also see that it has changed.
There is nothing to commit:
[[[language=bash
$ git status
On branch master
nothing to commit, working directory clean
]]]
If we repeat the process and we change one of our existent files, we will see something interesting:
[[[
$ cat project.txt
# Done
- created the repository
- git clone
- created this file
- commit this file
# To do
- push it to my remote repository
]]]
[[[language=bash
$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: project.txt
no changes added to commit (use "git add" and/or "git commit -a")
]]]
Indeed, changing again the file requires that we do a ==git add [file]== and ==git commit== again on the same file, even if Git already knew about it.
This is because Git will ask us to explicitly track ""every change"" we do.
So we will need to repeat the same operation of before.
[[[language=bash
$ git add project.txt
$ git commit -m "Commit is not in ToDo anymore"
[master e14a09f] Commit is not in ToDo anymore
1 file changed, 1 insertion(+), 1 deletion(-)
]]]
!!! Synchronizing with your Remote Repository
So far we have worked only on the local repository residing in our machine.
This means that mostly all of Git features are available without requiring an internet connection, making it suitable for working off-line (think on working on the train or with a constrained connection!). However, working off-line is a two-edged weapon: all your changes are captive in your machine.
While your changes are in your machine, nobody else can contribute or collaborate to them.
Moreover, losing your machine would mean losing all your changes too.
Keeping your changes safe means to synchronize them from time to time with your remote repository.
!!!! ==git pull==
@pulling_basic
Before being able to share our commits in some external server, we need before to update our repository to avoid them being de-synchronized.
While you can always try to share your commits by directly pushing (see Section *@pushing*), you will see with experience that Git favors pulling before pushing.
This is, among others, because in your local repository you can do whatever manipulation you want to solve mistakes and merge conflicts, while you cannot do the same in your remote repository.
For our example, pulling does not seem really necessary because you are the only person modifying your repository.
But let's imagine that you have done a modification in this same repository from another machine.
In that case, you would like to update your existing repository with the changes doing from this other machine.
Updating our repository is done through the ==git pull== command.
Pulling will update our database and then update our files.
[[[language=bash
$ git pull
remote: Counting objects: 2, done.
remote: Compressing objects: 100% (1/1), done.
remote: Total 2 (delta 1), reused 2 (delta 1), pack-reused 0
Unpacking objects: 100% (2/2), done.
From https://github.com/guillep/test
1656797..a2dbd8b master -> origin/master
Updating 1656797..a2dbd8b
Fast-forward
newfile | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 newfile
]]]
Three different scenarios can actually happen from a pull operation, which will be studied in detail in Section *@merging*:
- ""Fast-forward"": the updates were applied without needing a merge.
- ""Automatic Merge"": the updates were applied without conflicts. Git had to do a merge commit and will ask you for a commit message.
- ""Merge Conflict"": the updates could not applied. You need to manually resolve conflicts between your changes and the incoming changes.
Fast-forward and automatic merge are the simplest ones to manage since they require almost no manual interaction other than introducing a message.
!!!! ==git push==
@pushing
The final step in our Git journey is to share our changes to the world.
Such sharing is done by ""push""ing commits to a remote repository, as shown in Figure *@push_in_workflow*.
To push, you need to use the git command ==git push [remote] [remote_branch]==.
This command will send the commits pointed from your your current branch to the remote [remote] in the branch [remote_branch].
[[[language=bash
$ git push origin temp
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 271 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:[your_username]/[your_repo_name].git
b6dcc3f..f269295 master -> temp
]]]
+Push is an operation that sends commits from your local repository to a remote repository.>figures/push_in_workflow.pdf|width=90|label=push_in_workflow+
To avoid specifying the remote and destination branch on every push (which may be a bit verbose), you can avoid those parameters and rely on Git default values.
By default the ==git push== operation will try to push to the ""branch's upstream"".
A branch's upstream is the per-branch configuration saying to which remote/branch pair it should push by default.
When we clone a repository, the default branch comes with an already configured upstream.
We can interrogate Git for the branch's upstreams with the super verbose flag in the branch command, ''i.e.'', ==git branch \-vv==, where we can see for example that our ""master"" branch's upstream is ""origin/master"", while our ""development"" branch has no upstream.
[[[language=bash
$ git branch -vv # doubly verbose!
development 1656797 This commit adds a new feature
master f269295 [origin/master] First commit
]]]
On the other side, when a branch has no upstream, a push operation will by default fail with a Git error.
Git will ask us to set an upstream, or otherwise specify a pair remote/branch for each push.
[[[language=bash
$ git push
fatal: The current branch test has no upstream branch.
To push the current branch and set the remote as upstream, use
git push --set-upstream origin test
$ git push --set-upstream origin test
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 271 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:[your_username]/[your_repo_name].git
b6dcc3f..f269295 master -> test
]]]
Finally, another thing may happen while pushing: Git may reject our changes.
[[[language=bash
$ git push
To git@github.com:guillep/test.git
! [rejected] master -> master (fetch first)
error: failed to push some refs to 'git@github.com:[your_username]/[your_repo_name].git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
]]]
As the error message says, the remote has changes that we do not have locally, so we need to update our repository first.
This can be solved with a pull (Section *@pulling*) and a merge (*@merging*)
!!! Exercises (Guille 100%)
# ""Exercise 1"". Create an account in your preferred git repository hosting service, create there a repository and clone it. Then, check its history from the command line. How many commits are there in the repository? __Tip: there is a difference if you checked the "create README.md file" checkbox while creating a repository__.
# ""Exercise 2"". Create a file, a file inside a directory and an empty directory. Commit them (remember, ==git add==, ==git commit==). What can you see there? How does Git manage directories?
# ""Exercise 3"". If you're on a unix system (linux/osx), try changing your file's permissions and check ==git status==. How does git treat file permissions? Commit your changes and check the log. What can you observe?
# ""Exercise 4"". Push now your changes to your remote repository. Then, clone your repository again in another directory. Tip: try checking the help of the clone command ==git clone -h==. Did git save all your files, directories and even permissions?
# ""Exercise 5"". Go back to your first repository, add a new file, commit it and push it. Then go back to the second repository and pull. Inspect the history in both repositories: Is it the same?
# ""Exercise 6"". Check your online repository on your hosting service. Can you see the same state as in your local repositories? Go over the different tools offered by the hosting, they usually give some idea of the activity of the project, try to understand what they are for.