If you are used to work with GUI tool and want to learn the basics of working using the terminal, keep on reading.
In this readme you will find a step by step guided tutorial that will let you learn how to manage with terminal by doing.
In this repo you have a very simple project (a web project that displays a number via the console log), we will provide a guide to:
- Recreate the repo from scratch.
- Commit and push changes.
- Create branches.
- Merge branches.
- Resolve conflicts
We will use git terminal commands to setup and work with the repo.
Prerequisites to go through this tutorial:
It is important before starting to establish your username and email address, because this information will be appear in the "commits".
- Set up your username in Git
$ git config --global user.name "Test name"
- Set up your email address
$ git config --global user.email [email protected]
If you want to check your configuration, you can use the command:
$ git config --list
You can choose whether to use HTTPS (your standard git login user) or SSH (a more secure approach to treat with your repos but need some additional configuration).
More info about how to create an SSH key on your computer, and set it up on Git
To create the repo you can just click on the new repository button in Github or your favourite repository cloud provider.
When you create a new project, is a good idea to check the option to create a default readme.md file "creating" a default readme.md, by doing that we will get an initial commit done.
Now that you have your repo created is time to bring it to your local computer, in order to do that we clone it (download the repo to a local computer folder).
Ensure you have permissions to access that repositories, and if you are using SSH you have it properly configured (generated locally your ssh private and public keys, uploaded to your repository provider your public key).
Choose a folder to download the files, open a terminal window, and execute the following command:
git clone <repository_address>
Usually your git repo provider display an input where you can copy the url / ssh address of the repo to be cloned.
This is not related with Git, we are just creating a very simple web project to play with
Let's add some content to the repository.
We will start by creating a very simple web project (this is not related with Git, just setting up a nodejs project and a simple web project that displays a sentence via console log), let's execute the following command:
npm init -y
and install a bundler:
npm install parcel rimraf --save-dev
Let's create the following files under src folder:
./src/index.js
const sampleNumber = 1;
console.log(`Hello number ${sampleNumber}`);
Let's create a HTML entry point:
./src/index.html
<html>
<body>
<h1>Check the console log</h1>
<script src="./index.js"></script>
</body>
</html>
Let's add the following command to the existing package.json file:
./package.json
"scripts": {
+ "start": "rimraf dist && parcel ./src/index.html --open",
"test": "echo \"Error: no test specified\" && exit 1"
},
Time to give a quick check that the project is working, from the terminal execute:
npm start
A web browser will be opened and if you open the console log from that browser (e.g. on windows pressing F12) you can check that a message is displayed.
So far so good... now that we have a very simple project to play with, let's start interacting with Git!
Maybe we think we are now ready to make our first commit to master (the default branch has been created in our project).
Before making a commit let's check which files has been modified, open the terminal and type the following command:
git status
Wooooot !!! We have only created some files, Why we get a big ton of files in our list? Well npm install did it, you get under the node_modules a ton of files that you don't need in you repository (and you must not upload them), we have to ignore them, let's create a .gitignore file and include there the following content:
./.gitignore
/node_modules
/dist
/.cache
By doing that we are telling to ignore any path that includes node_modules to ignore it (do not taking into account in Git), click here to get more info about how to enter entries and patterns in a .gitIgnore.
Now if we execute again a status command we will see that only the files that we have created are pending to be added:
git status
Now if we want to push this changes to our git server, we need to perform three steps:
- First we need to mark that files as ready to be committed (you can do it file by file or you can select all files).
- Second you need to commit that staged files to your local git database
- Third now you can push these changes to the server.
Let's move the files to staging:
git add .
Now we can commit the files to our local database, we will add -m command to add a commit message:
git commit -m "initial project setup"
We are ready to upload the local changes that we have committed to the server:
git push
To check that everything went well, open your web browser, navigate to your git provider web client and check that the uploaded content is available.
Now that we now have taken our first steps using git is time to move forward, we are going to learn the basics of creating branches.
A branch allow us to create an isolated copy of the master branch (or any other branch) and let us work in that code cut isolated from the rest of the team, this is really useful to:
- Avoid adding not completed features to our product.
- Avoid impacting other developers in the team by adding changes into their code base.
- Reviewing the work done before merging that code into the master branch.
We want to implement a new functionality, display in the console log a second number. To avoid impacting other developers meanwhile we are progressing in our case we are going to create a branch. Let's create a new one:
git branch feature/display-number-b
About the naming convention used to define the branch name, we are using gitflow, click here to get more info about how to name branchs and gitflow
We can execute the command git branch to check that the branch has been created, this command will indicate us as well the active branch (master):
git branch
Let's switch from our master branch to the feature/display-number-b
git checkout feature/display-number-b
You can switch from a given branch to another if the active branch has no changed pending to be committed (if the active branch has changes pending to be committed, you have to commit them, discard them or stash them, we will check all this later on).
Another faster way to create a branch and switch to it is as follows:
git checkout -b feature/display-number-b
Now we can start working on our branch without impacting users that are working on the master branch.
Let's add some updates in the .src/index.js files:
./src/index.js
const sampleNumber = 1;
+ const sampleNumberB = 2;
- console.log(`Hello number ${sampleNumber}`);
+ console.log(`Hello number ${sampleNumber} {sampleNumberB}`);
Save the changes, and add them to staging:
git add .
This command adds to the index any new file or modified file.
Commit them to our local database:
git commit -m "adding one more number"
And push them to our remote origin (in this case the branch new created branch does not existing in the server, we need to add some extra parameters to indicate the origin to create the branch).
git push -u origin feature/display-number-b
Now we could merge this remote branch to master, but we won't to do this right now: we will first simulate that in between that time another developer has created another branch and modified the ./src/index.js file creating a conflict, we will learn how to sort this out in the following section.
Some good advice: never merge from a given branch to master using the command line, rather raise pull requests and review the code (you can raise pull request from a given branch to master using the web client your favourite repository), on the other hand is a good practice to merge master into your branch using the terminal, this will let update your codebase to the current master status.
Before merging our new branch to master, let's simulate that in the mean time another developer (or ourselves) has created a second branch and it's modifying the files that we have just updated.
Let's hop in the master branch:
git checkout master
Let's create a new branch from master:
git branch feature/display-number-c
Let's jump into that branch
git checkout feature/display-number-c
Let's update the index.js file and include a numberC to be displayed
/.src/index.js
const sampleNumber = 1;
+ const sampleNumberC = 3;
- console.log(`Hello number ${sampleNumber}`);
+ console.log(`Hello number ${sampleNumber} ${sampleNumberC}`);
Let add stage the updated file:
git add .
Let's commit this file
git commit -m "Adding third number"
Let's push the changes
git push -u origin feature/display-number-c
Let's check the list of branches we have available:
git branch
We got three branches: master, feature/display-number-b, feature/display-number-c and the active one is feature/display-number-c
We got the ok from the team to merge branch feature-display-number-b into master, let's got for it.
Let's switch to master branch
git checkout master
Let's merge featute/display-number-b it in master:
git merge feature/display-number-b
A good practice before merging with master is to ensure the branch is updated with the latest master cut (merge from master to our branch)
We can do this because we go the branch available locally, if it's a branch created by another user it may happen that is available in the server but not in our local computer, we have to execute fetch to bring it locally (check Misc section).
In this case there are not conflicts, we are good to go.
Let's push the updates.
git push
Now you can use your web browser and navigate to your provider web repository page and check that the changes are reflected, that was great!
Let's start with a hard one... we want to merge feature/display-number-c into master Why is a hard one? Because the version of master that was taken as starting point to create feature/display-number-c is different from the actual one, and it has conflicts (index.js file got updated on both versions), we need to resolve the conflicts and choose what's the right piece of code to work with.
Let's try to merge feature/display-number-c into master.
Let's ensure first that we are on master branch, by executing git branch command we get the list of branches available and highlighted the active branch.
git branch
Now let's merge this branch into master
git merge feature/display-number-c
Ouch we got merge conflicts !! Now we have to fix them running the git mergetool command.
Before running this command, let's make the following check, do you have a merge tool installed and configured? If not jump to the section Misc/Setting up a merge tool in this readme.
Let's run the command to start the merge:
git mergetool
Depending on your configuration a given tool will be launched (KDiff, VSCode, p4merge...), you have to go through the conflicts and choose (usually you have to choose conflict by conflict): - Whether to preserve your local changes and discard the merging branch changes. - Whether to apply your merging branch changes to master. - Apply your own code update or manual merge.
Depending on the tool it will try to auto-resolve some merge conflicts for you.
If you don't have a mergetool configured, or want to learn more about it, check the section Misc/Setting up a merge tool.
Once you got all your conflicts solved, let's add them to staing and is to commit them:
git add .
git commit -m "fixing merge conflicts"
Some developers may prefer to use a UI tool to manage this (e.g. Source Tree, Git Kraken, VSCode), mileage applies.
Now we can push the changes to the remote origin:
git push
Did you get a lot of temporary *.orig files? you can config your Git local installation by telling not to keep that files:
git config --global mergetool.keepBackup false
-
You can create a new local folder for your repository or you can choose another project folder which you already wanted to upload to Github.
-
Open the terminal and locate yourself in the project folder. In order to create a new database it is necessary to write the next command-line (if you have already done this step before, the database will not be created again but reinitialized):
git init
- Next, the local database must get linked with the Github repository. In order to do that, it is necessary to log in Github and create a new blank repository (without initializing it with a README file). Afterwards, you can copy the url of the repository and write it in the next command-line:
git remote add origin https://github.com/...
- At the moment, the local database and the Github repository must have been linked already. Therefore, you can proceed to upload the files, but first it is necessary to put them in staging:
git add .
- Now you must save the files in the local database:
git commit -m "comment"
- Finally, everything is ready to upload the files to Github. However, using push is not enough since it is necessary to set the master branch of the repository first:
git push --set-upstream origin master
Setting up a merge tool can be a tough decisition there are many available, e.g.:
- Kdiff
- VSCode
- p4Merge
- ...
In this post you can check tools available for Windows, in this other for Linux, and for Mac Os guys, check this post.
How to setup a diff tool in Mac Os
e.g:
Setting up Kdiff on windows:
- Install Kdiff, you can download it from here
- Open the terminal and run the following commands:
git config --global --add merge.tool kdiff3
&&
git config --global --add mergetool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
&&
git config --global --add mergetool.kdiff3.trustExitCode false
&&
git config --global --add diff.guitool kdiff3
&&
git config --global --add difftool.kdiff3.path "C:/Program Files/KDiff3/kdiff3.exe"
&&
git config --global --add difftool.kdiff3.trustExitCode false
Setting up Kdiff on mac:
- Install Kdiff, you can download it from here
- Open the terminal and run the following commands:
git config --global --add merge.tool kdiff3
&&
git config --global --add mergetool.kdiff3.path "Applications/kdiff3.app/Contents/MacOS/kdiff3"
&&
git config --global --add mergetool.kdiff3.trustExitCode false
&&
git config --global --add diff.guitool kdiff3
&&
git config --global --add difftool.kdiff3.path "Applications/kdiff3.app/Contents/MacOS/kdiff3"
&&
git config --global --add difftool.kdiff3.trustExitCode false
When you are working locally in your repository, if you want to commit changes you need to perform to steps: first add the files to staging, then commit that files.
What can you do if you have added to staging a temporary file? You can remove it from stage by executing the following command:
git reset HEAD <filepath>
And... if you want to remove all files from staging?
git reset HEAD .
That was great, but what if want to discard changes on a file that was not on staging?
git checkout --
Last but not least... discard everything, I want to start from that fresh commit again:
git checkout HEAD
When we work on a team, there may be branches that have been uploaded to the remote server that are not avialable in our local repository, how can I download them? you can execute:
git fetch --all
From time to time, there are branches that may not exists anymore on the remote server but you keep them locally, how can you make some cleanup and remove those unused branches refs locally, to do that we can execute:
git fetch --prune
There are times that a given person is working in the same branch you are working on and you need to pull the changes from the server branch to your branch, we cannot do this making a fetch, since it could generate conflicts, in that case we use git pull, this will download the content of the active branch from the remote server and try to merge it with your current cut.
git pull
Sometime you are working in your codebase on some temporary code that you don't want to commit yet, but you need to quick switch to another branch, but... you cannot switch without committing or discarding your temporary code. Is there any way to put that temporary code "into a drawer" and once you comeback to that commit be able to restore it? That's exactly what stash does.
Let's create a new branch and call it feature/saygoodbye
git branch feature/saygoodbye
Let's switch into that branch
git checkout feature/saygoodbye
Let's update some code:
./src/index.js
const sampleNumber = 1;
const sampleNumberB = 2;
const sampleNumberC = 3;
console.log(`Hello number ${sampleNumber} {sampleNumberB} {sampleNumberC}`);
+ console.log('Goodbye !');
- We don't want to commit yet, but we need to jump into master... what can we do? Stash our changes (both staged and unstaged files will be stored locally):
git stash
- Now we can hop into master
git checkout master
- Switch back to feature/saygoodbye branch.
git checkout feature/saygoobdye
- And recover the code that we store in stash
git stash pop
Stash store this information locally and are associated to the specific commit where stash was invoked.
Sometimes you need to migrate some repository to another one and you really want everything, including all branches, refs, tags, etc.
Instead of using a standard clone
, we can follow these steps:
- Clone original repository locally
again
but with themirror
flag:
git clone --mirror <origin url>
- It will create a folder with the
repository-name.git
and it will clone the current repository stuff, something like:
- Change terminal to the new directory:
cd <cloned folder>
- And push everything to the new
url repository
usingmirror
flag:
git push --mirror <destination url>
Some useful Github cheat sheets:
- https://i.redd.it/8341g68g1v7y.png
- https://www.git-tower.com/blog/git-cheat-sheet/
- https://github.github.com/training-kit/downloads/github-git-cheat-sheet.pdf
We are an innovating team of Javascript experts, passionate about turning your ideas into robust products.
Basefactor, consultancy by Lemoncode provides consultancy and coaching services.
Lemoncode provides training services.
For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend