Git - DavidBK/shampoo GitHub Wiki
Estimation time: 3 Days
Git is a free and open source distributed version control system.
The reason you are learning it is because Git is the most popular version control system in developing. It is also used in the next steps of your learning process.
Make sure you understand the learning concepts but Don't memorize them!
Learning objectives:
After completing this learning module, you'll be able to
- Control the version of your code
- Collaborate with other developers
- Share your code with others
- Track your code changes
Send me back home
[[TOC]]
Learning note: all links in this path are reading tutorials. You can read them but you can watch a youtube crash course on git or just play with the commands by yourself. If you find useful links, please share them with me.
Make sure you can perform all the commands live (with google help). You'll be tested on this.
Here are some examples links:
Git is a version control system for tracking changes in files and coordinating work among multiple people.
Open Terminal and enter:
sudo apt install gitcheck if git is installed:
git --version(If you don't use WSL look up how to install git on windows)
The Git configuration file contains a number of variables that affect the Git
commands' behavior. The .git/config file in each repository is used to store
the configuration for that repository, and $HOME/.gitconfig is used to store a
per-user configuration as fallback values for the .git/config file.
We will use this git-config to set up
the Git configuration file.
Replace "Your Name" with your preferred username:
git config --global user.name "Your Name"Replace "[email protected]" with your email:
git config --global user.email "[email protected]"Attached to this project is my .gitconfig file. You can use it to build your awesome
.gitconfig! Don't forget to share it with me. 😂
Git uses several protocols for client-server communication. SSH and HTTPS are secure protocols. As a result, many git servers, such as Github, Bitbucket, and GitLab, use those two popular cryptographic network protocols.
HTTPS is a secure version of HTTP that encrypts data transmitted between the client and the server.
Starting git with HTTPS for cloning, pulling, and pushing is much easier and can be done with much less setup.
If you use HTTPS URLs on the command line to get a remote repository, git fetch, git pull, or git push, git will ask for a username and password.
SSH means "Secured Shell". It is also a secured version, where data sent between the client and server is encrypted.
- How does SSH work? (Enrichment - Optional)
Open terminal and type:
ssh-keygenPress Enter. Output similar to the following is displayed:
Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):Accept the suggested filename and directory.
Specify a passphrase if you like.
A public and private key are generated. Add the public SSH key to your Remote account and keep the private key secure.
(In github and bitbucket the process is the same)
You can read this for more details: add-an-ssh-key-to-your-gitlab-account.
-
Copy the contents of your public key file
cat ~/.ssh/id_rsa.pub | clip.exe
-
Your avatar > Preferences > SSH Keys > Add SSH Key
-
Paste the contents of your public key file into the
keybox. -
In the Title box, type a description, like
Work Laptop
Verify that you can connect using ssh!
ssh -T [email protected]Learn the basic git commands and how to use them.
Try it yourself! Init a git repo and create commits and branches. merge them and play with the git commands.
Understanding the practical use of git will help you to understand the next steps. In the next chapter we dive more deeply into the concepts.
If you like to learn by a game, you can try this one:
Make sure you know the following commands:
addcommitlogstatusdiffstash
Commits messages have two parts:
- The title
- The body
The body is optional. Even though I think it is a good idea to write a body, most of the time the message is only the title.
There is several conventions for commit messages but they Follow the same general rules.
Here is our convention for commits title:
- Commit messages start with a Capital letter -
Add commit message(notadd commit message) - Commit messages start with a verb -
Add text1(notText1 commit) - The verb should be present-tense, imperative-style -
Fix bug x(notFixing bug x,Fixed bug x) - an explanation for people who hate present-simple: Think: 'If I use the commit I will ... (Add a feature, fix a bug etc.)
Note: It is often helpful when you are creating temporary commits to write down for yourself that they are temporary and what for. For example:
TEMP try to fix a bug - not working
FIXUP a previous commit
WIP work in progress
That way it is easier to perform rebases.
- What is the commit hash?
- How is it made?
- Based on the previous question, what can change the commit hash?
- So, What is the point of this hash recipe?
- How much code should be in one commit?
- Can the same code be in different commits?
- How do I commit changes to previous commits?
- When should I commit?
- How can I see what's added in each commit?
commit VS stash:
- What's the benefit of
commit? What's the benefit ofstash? - Based on the previous question, when should I use which one?
Make sure you know the following commands:
checkoutswitchrestorermresetrevertreflog
Many think that git reflog operates kind of like ctrl-z - undo situation. This
is not the correct way to think about it. And it becomes impossible to track all
the git operations in reverse order.
Think about the reflog as a list of pointers and hints about what was "saved" in
them. For example, if you lost a pointer for a commit, look for a git operation
that represents the commit like commit or checkout.
- How do I delete a commit?
- What are the three types of
reset? when should I use each one? - What's the difference between
resetrevertrmandrestore? - Why should I never want to use
revert?
- What does git save in order to manage the version control?
- What is
HEAD? How do I change it? What isHEAD^^andHEAD~2? - How does branching works? Why is it implemented that way?
- How do I move a branch to point to a specific commit in my history?
- How do I move a branch to a different pointer (What can be a pointer for this)?
- Can reset add code to my HEAD? Can it add a commit?
- What happens to the commit when I reset them?
- How do I undo a reset when I have the pointer?
- How do I undo a reset when I don't have the pointer?
make sure you know the following commands:
checkoutbranchmergerebase
- What is a branch? What should be in a branch?
- What is
master/main? For what purpose they are used?
- What is the difference between
mergeandrebase? - What is the benefit of
merge? What is the benefit ofrebase? You can use this topic in your answer:- Creation and Conflict resolution
- Undoing the union
- History changes
- History log (story-telling)
- Based on the previous question, when should I use which one?
- When are the merge and rebase results are the same?
- What are conflicts? When do they happen?
- How do I resolve conflicts?
-
How can I modify a commit in the branch's history?
-
Is it possible to modify a commit in the history by using
reset? how? why? -
How can modified commits can be scaled? What will happened when there are large changes to multiple files across multiple commits in a large code-base?
If you don't understand this question, we will return to it in the Project chapter.
Learn how to use the GUI of git. You can read this article version control git-support.
- How do I
add,commitandresetfrom the VS code GUI? - How do I
diffchanges? - How do I solve conflicts in the VS code editor?
You can use the VS code GUI according to your comfort.
Make sure you know the following commands:
remote-
push,--set-upstream pullfetchclone- fork
It's better to initialize a project on the remote. The remote offers an initializing commit and basic README.md file. Some remotes offer more standardized files depending on the language.
Whether you have a git project or not, you can start working on it by cloning the project on your computer.
git clone [email protected]:/path/to/repo.gitStart a "split" in the history of main branch by using:
git checkout -b feature-branchThere is no branch naming convention and it depends on the team and the project. But it is a good idea to use meaningful names which everyone will understand and can tell by the name what the branch is for.
For example, dev and dev2 are not such great names for a branch...
Sometimes there is a "master"-like branch. which is used for the main
development branch. Usually named dev or development, but make sure to
protect this branch from unwanted pushes and irresponsible behavior.
Side-note: If you have tab completion for the branch names then it is fine to use long branch names, but if not it is recommended to keep them short.
Regularly push your work to the remote - The rule is that you should loose your computer always without sorry about your work (Bummer for your computer).
Never Work on the main branch!
The main branch is the operational branch. It is the "production-like" code -
that is being used by others so if you change the history, it can break other's
systems and create conflicts if they are developing on parallel branches. Code
can't just be pushed into this branch. (You can define in the remote that nobody
is allowed to push to this branch).
In order to enter the main branch, you need to Request a merge! this process
is called "Merge Request" (on Gitlab) and "Pull Request" (on GitHub) and
shortly called "PR".
After you have requested a merge, you can see a PR (MR) in the "Pull/Merged Requests" tab. Usually someone will review your MR and review your code. this process called "Code Review" or "CR".
The code review is important to keep the shared code clean and without bugs. Also it is the best way to learn and evolve as a developer! don't be afraid to get a criticizing review, but also don't be shy to answer and argue about comments that you don't agree with (or understand). The final decision is to the code maintainer (sometimes that is you), but your opinion is important.
NOTE: In some agile ci-cd methodologies, the code review is skipped, and instead comments become future issues. There are benefits and drawbacks to this methodology. Can you tell what is the best for you?
After you get a code review, you can fix the code.
Fix the code in the same branch, and the corresponding commit!
NOTE: Sometimes the maintainer will ask for new commits that fix the code
review. This is fine and recommended but it demands to squash those commits
before merging
After the fixing and committing you can push your changes to the remote to
same branch. The PR is automatically updated.
Sometimes while coding and reviewing, and fixing, the main branch is updated,
and may cause conflicts. Even when there are no conflicts, our PR branch needs
to have linear history compered to the main branch.
To organize the commits of our PR we will need to pull the origin main
branch, and rebase with it.
There is a one line command for this (make it alias!)
git pull --rebase origin mainReview, again
After pushing the rebased branch to the remote (Which will update the PR), the code will be reviewed again.
This is an iterative process of Review - Fix - Rebase until The maintainer decides to accept the PR.
Sometimes there is a bug or code that needs fixing in the main branch. In
these cases we will create a new branch and fix the code. In very rare cases
the maintainer will revert the merge request commit!
- What is "Remote"? what is
origin? - How can a project can have multiple remotes?
- How does
origin/branchcan differ frombranch? How do you set them back? - How does the local repo "know" that something happened in the remote?
- What is the
main(pun intended) purpose of the workflow process? - When do I use the
mergecommand locally? why?
make sure you know the following commands:
config
-
What is git alias?
-
How do you show all git aliases?
Lets go meta! - make an alias to show all git aliases 😄
-
What is
.gitconfig? Where is it located? -
What is
!gitin the.gitconfig?
Attached to this project is my .gitconfig file. You can use it to build your awesome
.gitconfig! Don't forget to share it with me. 😂
Lets write Space Book!
General hint: Note that all chapter follow the order of this tutorial, and you can use the "Learning Topic" link at every chapter.
Write Prologue: - Learning Topic
- Init a new project on the remote, and clone it locally.
- Create new dir named
private-ideas. - Add
.gitignorefile to the project. addprivate-ideasto the.gitignorefile. -
commitit with appropriate message.
Write Chapter 1: - Learning Topic
- Create a new branch called
chapter-1from themainbranch. - Add 3 files with
page-<n>.md(in the workspace dir) with<n>represent the page number. - Create 3 corresponding commits.
- At the end of page 3, add this text
# The spaceship is gone! - Add this text to the last commit. Prove yourself that all the pages in the right commit.
Write Chapter 2: - Learning Topic
- Create a new branch called
chapter-2, which will point on thechapter-1branch. - Change the name of the last commit to
Add page 3 to chapter 2. - Add a new line to this page with the text
This is page 3 - chapter 2and Commit it with the messageAdd a mistake. - Oops this is a mistake. Who could know! I forgot that this new line souled be
in the commit
Add page 3 to chapter 2. My bad... Fix it.
Write Chapter 3: - Learning Topic
-
Create a new branch called
chapter-3, which will point on thechapter-1branch. -
Make Chapter 3 empty with no commits expect
Initial commit. -
Log the all history with a graph. look at HEAD, and the branches pointers.
Your graph should look like this:
* 7c67cad - (chapter-2) Add page 3 to chapter 2 (61 seconds ago) <space-name> | * cf15fb8 - (chapter-1) Add page 3 (7 minutes ago) <space-name> |/ * 9e37807 - Add page 2 (8 minutes ago) <space-name> * 9684685 - Add page 1 (8 minutes ago) <space-name> * ebd3885 - (main) Add .gitignore (10 minutes ago) <space-name> * 8975347 - (HEAD -> chapter-3, origin/main, origin/HEAD) Initial commit (12 minutes ago) <Space Name>If not it is ok! Do not continue... Just make it look like this.
Write Chapter 4: - Learning Topic
-
Create a new branch called
chapter-4, which will point on thechapter-3branch. -
Make chapter 4 point on chapter 2.
-
Add file name
this_is_not_a_book.txtand commit it. -
Make a branch called
chapter-4-ver-2which will point on thechapter-4branch. -
Reset (hard) the last commit to
Add page 3 to chapter 2. -
Oh no! I was confused between
chapter-4-ver-2andchapter-4. Silly me.Swap the
chapter-4-ver-2andchapter-4branches. Do not create a new branch!
Write Chapter 5: - Learning Topic
-
Create a new branch called
chapter-5which will point on theAdd a mistakecommit. -
Log the all history with a graph. Your graph should look like this:
* 05b2320 - (chapter-4-ver-2) Create this_is_not_a_book.txt (3 minutes ago) <space-name> * 7c67cad - (chapter-4, chapter-2) Add page 3 to chapter 2 (13 minutes ago) <space-name> | * f36ad71 - (HEAD -> chapter-5) Add a mistake (14 minutes ago) <space-name> | * 137d2d8 - Add page 3 to chapter 2 (18 minutes ago) <space-name> |/ | * cf15fb8 - (chapter-1) Add page 3 (20 minutes ago) <space-name> |/ * 9e37807 - Add page 2 (20 minutes ago) <space-name> * 9684685 - Add page 1 (20 minutes ago) <space-name> * ebd3885 - (main) Add .gitignore (23 minutes ago) <space-name> * 8975347 - (origin/main, origin/HEAD, chapter-3) Initial commit (24 minutes ago) <Space Name>If not it is ok! Do not continue... Just make it look like this.
Write Chapter 6: - Learning Topic
-
Create a new branch called
chapter-6which will point on thechapter-1. -
Create a file named
page-4.md, add a line# page-4and commit it. -
Create a new branch called
chapter-6-ver-2which will point on thechapter-1branch. -
Create a file named
page-4.md, add a linepage 4and commit it. -
Add a line
## What happens to the spaceship?and amend it to previous commit. -
merge
chapter-6intochapter-6-ver-2. -
Resolve conflict such that page 4 look like this:
# page-4 ## What happens to the spaceship?
-
Sorry, I meant to merge
chapter-6-ver-2intochapter-6. Why, it's a problem? Fix it. -
merge
chapter-6intochapter-5branch. Resolve the conflict. -
merge
chapter-5intomainbranch. What is the merge commit? -
Log the all history without a graph. What is the "story" log of the main branch?
Log the all history without a graph, Your graph should look like this:
* 4c61fe9 - (HEAD -> main, chapter-5) Merge branch 'chapter-6' into chapter-5 (3 minutes ago) <space-name> |\ | * bea46bd - (chapter-6) Merge branch 'chapter-6-ver-2' into chapter-6 (8 minutes ago) <space-name> | |\ | | * a199dd5 - (chapter-6-ver-2) Add page 4 (10 minutes ago) <space-name> | * | 8d1c0d2 - Add page 4 (12 minutes ago) <space-name> | |/ | * cf15fb8 - (chapter-1) Add page 3 (34 minutes ago) <space-name> * | f36ad71 - Add a mistake (28 minutes ago) <space-name> * | 137d2d8 - Add page 3 to chapter 2 (32 minutes ago) <space-name> |/ | * 05b2320 - (chapter-4-ver-2) Create this_is_not_a_book.txt (18 minutes ago) <space-name> | * 7c67cad - (chapter-4, chapter-2) Add page 3 to chapter 2 (28 minutes ago) <space-name> |/ * 9e37807 - Add page 2 (35 minutes ago) <space-name> * 9684685 - Add page 1 (35 minutes ago) <space-name> * ebd3885 - Add .gitignore (37 minutes ago) <space-name> * 8975347 - (origin/main, origin/HEAD, chapter-3) Initial commit (39 minutes ago) <Space Name>If not it is ok! Do not continue... Just make it look like this.
-
As we learned in Workflow we don't merge local branches into the
mainbranch. Set back main to point onorigin/main
Write Chapter 7: - Learning Topic
-
Create a new branch called
chapter-7which will point on thechapter-6. -
reset --hardthe last commit (Merge branch 'chapter-6-ver-2' into chapter-6). -
Create a new branch called
chapter-7-ver-2which will point on thechapter-6-ver-2. -
Log the all history with a graph. Notice that Chapter 7 is now in the same as Chapter 6 in section 5.
We will rebase it instead of merging (As one should).
* 4c61fe9 - (chapter-5) Merge branch 'chapter-6' into chapter-5 (8 minutes ago) <space-name> |\ | * bea46bd - (chapter-6) Merge branch 'chapter-6-ver-2' into chapter-6 (13 minutes ago) <space-name> | |\ | | * a199dd5 - (HEAD -> chapter-7-ver-2, chapter-6-ver-2) Add page 4 (15 minutes ago) <space-name> | * | 8d1c0d2 - (chapter-7) Add page 4 (17 minutes ago) <space-name> | |/ | * cf15fb8 - (chapter-1) Add page 3 (39 minutes ago) <space-name> * | f36ad71 - Add a mistake (33 minutes ago) <space-name> * | 137d2d8 - Add page 3 to chapter 2 (37 minutes ago) <space-name> |/ | * 05b2320 - (chapter-4-ver-2) Create this_is_not_a_book.txt (23 minutes ago) <space-name> | * 7c67cad - (chapter-4, chapter-2) Add page 3 to chapter 2 (33 minutes ago) <space-name> |/ * 9e37807 - Add page 2 (39 minutes ago) <space-name> * 9684685 - Add page 1 (40 minutes ago) <space-name> * ebd3885 - Add .gitignore (42 minutes ago) <space-name> * 8975347 - (origin/main, origin/HEAD, main, chapter-3) Initial commit (44 minutes ago) <Space Name> -
Rebase
chapter-7-ver-2on top ofchapter-7. Resolve the conflict. -
I must be a real dumb, i meant to rebase
chapter-7on top ofchapter-7-ver-2. Fix it. (Hint: you don't have to usereflog) -
Log the history of
chapter-7andchapter-6. Compere them and answer the question union-of-branches again.Your graph should look like this:
* dd17043 - (HEAD -> chapter-7) Add page 4 (43 seconds ago) <space-name> | * 4c61fe9 - (chapter-5) Merge branch 'chapter-6' into chapter-5 (17 minutes ago) <space-name> | |\ | | * bea46bd - (chapter-6) Merge branch 'chapter-6-ver-2' into chapter-6 (21 minutes ago) <space-name> | | |\ | |_|/ |/| | * | | a199dd5 - (chapter-7-ver-2, chapter-6-ver-2) Add page 4 (23 minutes ago) <space-name> | | * 8d1c0d2 - Add page 4 (26 minutes ago) <space-name> | |/ |/| * | cf15fb8 - (chapter-1) Add page 3 (48 minutes ago) <space-name> | * f36ad71 - Add a mistake (42 minutes ago) <space-name> | * 137d2d8 - Add page 3 to chapter 2 (46 minutes ago) <space-name> |/ | * 05b2320 - (chapter-4-ver-2) Create this_is_not_a_book.txt (31 minutes ago) <space-name> | * 7c67cad - (chapter-4, chapter-2) Add page 3 to chapter 2 (41 minutes ago) <space-name> |/ * 9e37807 - Add page 2 (48 minutes ago) <space-name> * 9684685 - Add page 1 (48 minutes ago) <space-name> * ebd3885 - Add .gitignore (51 minutes ago) <space-name> * 8975347 - (origin/main, origin/HEAD, main, chapter-3) Initial commit (52 minutes ago) <Space Name>
Write Chapter 8: - Learning Topic
-
Create a new branch called
chapter-8which will point on themain. (As usual workflow) -
Delete all the content of the
README.mdfile. -
Add this text to the readme:
# space book i am a space book ## the end
-
Commit the readme into three corresponding commits.
Add book titleAdd book bodyAdd book end -
Push the branch
chapter-8to the remote. -
Open a PR from
chapter-8tomain. -
Go to the pr and give yourself some feedback! Comment on each commit the following:
Add book title: "Book title should be in Capital lettersSpace Book"Add book body: "New Line Should start with a Capital letterI", "Add period at the end of the sentence", "Change commit message toAdd book content"Add book end: "```suggestion:-0+0The End```" -
Fix the commit in respect to the feedback.
-
What is the last shared commit between
chapter-8andorigin/chapter-8? -
Push the branch
chapter-8to the remote. -
Approve the PR.
Write Chapter 9: - Learning Topic
-
Create a new branch called
chapter-9which will point on thechapter-7. -
Organize your commit (Do you have redundant commits that need a
squash?). -
Push the branch
chapter-9to the remote, and make a PR fromchapter-9tomain. -
Now we will use more robust way to modify commits. Let's say we have a huge bug in page-2, and some code to add to page-3.
-
Fix the bug in page-2. Add this clever code to page-2:
\ / .\-/. /\ () () / \/~---~\.-~^-. .-~^-./ | \---. { | } \ .-~\ | /~-. / \ A / \ \/ \/ -
Commit the fix to page-2 with temp name like
fix page-2(OrFIXUP page 2). -
Add the code to page-3:
.___ ____ ____ __| _/____ _/ ___\/ _ \ / __ |/ __ \ \ \__( <_> ) /_/ \ ___/ \___ >____/\____ |\___ > \/ \/ \/ -
Commit the code to page-3 with temp name like
fix page-3(OrFIXUP page 3). -
rebase -iwith fixup (f) option and inject the fixes commit in the right places. -
Nice! push your branch to the remote.
-
Approve the PR after you put
chapter-9on top oforigin\mainbranch. -
Pull the
main.
-
Epilog:
Copy the commit Add a mistake to chapter-3 branch. Resolve the conflict by
accepting the all page-3. checkout to the main and print all the commits in
the graph.
How was your story?? I hope its look like this:
* 81dda3f - (chapter-3) Add a mistake (36 seconds ago) <space-name>
| * c2d0098 - (HEAD -> main, origin/main, origin/HEAD) Merge branch 'chapter-9' into 'main' (2 minutes ago) <Space Name>
| |\
| | * c80c1f1 - (origin/chapter-9, chapter-9) Add page 4 (3 minutes ago) <space-name>
| | * 81591e8 - Add page 3 (3 minutes ago) <space-name>
| | * d1c1453 - Add page 2 (3 minutes ago) <space-name>
| | * 5a4f26a - Add page 1 (3 minutes ago) <space-name>
| |/
| * 103e66c - Merge branch 'chapter-8' into 'main' (6 minutes ago) <Space Name>
|/|
| * e7c6ee5 - (origin/chapter-8, chapter-8) Add book end (6 minutes ago) <space-name>
| * 7701fdd - Add book content (6 minutes ago) <space-name>
| * 105e80f - Add book title (6 minutes ago) <space-name>
| | * dd17043 - (chapter-7) Add page 4 (18 minutes ago) <space-name>
| | | * 4c61fe9 - (chapter-5) Merge branch 'chapter-6' into chapter-5 (34 minutes ago) <space-name>
| | | |\
| | | | * bea46bd - (chapter-6) Merge branch 'chapter-6-ver-2' into chapter-6 (38 minutes ago) <space-name>
| | | | |\
| | | |_|/
| | |/| |
| | * | | a199dd5 - (chapter-7-ver-2, chapter-6-ver-2) Add page 4 (40 minutes ago) <space-name>
| | | | * 8d1c0d2 - Add page 4 (42 minutes ago) <space-name>
| | | |/
| | |/|
| | * | cf15fb8 - (chapter-1) Add page 3 (65 minutes ago) <space-name>
| | | * f36ad71 - Add a mistake (59 minutes ago) <space-name>
| | | * 137d2d8 - Add page 3 to chapter 2 (63 minutes ago) <space-name>
| | |/
| | | * 05b2320 - (chapter-4-ver-2) Create this_is_not_a_book.txt (48 minutes ago) <space-name>
| | | * 7c67cad - (chapter-4, chapter-2) Add page 3 to chapter 2 (58 minutes ago) <space-name>
| | |/
| | * 9e37807 - Add page 2 (65 minutes ago) <space-name>
| | * 9684685 - Add page 1 (65 minutes ago) <space-name>
| |/
| * ebd3885 - Add .gitignore (68 minutes ago) <space-name>
|/
* 8975347 - Initial commit (69 minutes ago) <Space Name>
If not it is ok! After all this is your book...
Talk to your mentor about the exam.
These concepts are worth mentioning but don't learn them now.
Congratulations! You have completed the Git module. now you can control the source code of your space 😄
Here is the next Learning Path