Sunday, September 22, 2019

Git for developers

part of: JavaScript for beginners - learn by doing

Let's start with the following facts there are three areas in git: working directory-staging(index)-history(commits). All of them contain snapshot versions of your working files. Here are two videos on the topic:






From then on a sample Git workflow is as follows:

1. We need to set up a repository with git init . This will turn our local folder into a Git repository. And if we want to start from an already existing project, we can do this, by copying the remote project on our local machine. We can use git clone git address .
From then on git will track all the new files/directories, file changes or deletions inside our directory space. Note: If we don't want certain files to be tracked for changes by Git, we can place them inside: .gitignore file (files such as /node_modules/ directory)

2. Then, when we have completed our work on files (created new ones or updated code functionality) we can add them inside the staging area using git add filename.ext

3. As the last step on our local machine we save all the staged files as 1 commit inside the history area: git commit -m "message of the commit"

Why to use branches
Branches are useful because they enable multiple developers to: work on several features, fix bugs, independently etc... all this on a single repository.
To create a branch you can use: git branch [branch_name]. Since you are currently checked out to a branch it's last commit will be used as a starting point of the newly created branch. To go to the branch (its first commit) you use: git checkout [branch_name]. Note: If you would like to start developing from a certain commit onwards, just first checkout the commit and then type git checkout -b [commit_name]. This will automatically create a new branch with initial commit = the last checked out commit of the last checked out branch.

Must know: Git uses both HEAD pointer to branch reference or commit, as well as a branch pointer to a commit. By default, they go together and point to the same place.

We can view all the saved commits we made with: git log. Please pay attention to the commit ids. They are unique and we can use them to navigate between the commits using: git checkout commit_id -- file_to_restore.ext or git reset --hard commit_id. They will change the contents of the files, create new ones and even delete them.
The differences between the two commands are:
- with git reset, we are reverting to previous commit all the files, while with git checkout we can choose which specific files to revert
- git checkout: detaches only the HEAD pointer from the currently checked out branch (reference) and changes it to the reset commit. Checkout is used as a temporary switch to the previous commit.
Detached HEAD means we are not on a branch (we are on commit) but are not checked in a branch.
So we have 2 options to create new branch from the current commit or to return to (check out) an existing branch. To create new branch and work from this commit onward we use: git checkout -b new_branch. To return back while checking out particular branch we use: checkout master or git checkout @{-1}

- git reset moves both the HEAD + branch ref to the reset commit (while keeping the HEAD pointer attached to the currently checked out branch). Reset is a preferred way for undoing actions (while programming) and returning to previous code states (commits).

Errors can occur while playing with those commands: for example when we are trying to check out to a different branch while still have uncommitted changes from the current. In such cases we either:
commit the work and switch to the other branch(checkout) or we are not ready to commit so we can save temporary the work by typing: git stash, then we can do reset/checkout to another branch/commit. Later when we want to reapply our changes to the current code we are exploring we can just get them out of the stash with: git stash pop.

Remotes
In order to share work with other programmers, we would like to send to and pull (fetch + merge) changes from remote repositories called remotes. From then on we can create a local branch that tracks the remote equivalent branch on the remote repository (remote tracking branch). The easiest way to create such branch so is to use the same names for the remote and local branches when creating the local branch.
Steps:
1. create&checkout to branch with: git checkout -b new_branch
2. set the tracking for the local branch (to track the remote branch)
git branch --set-upstream-to=origin/local_branch_name remote_branch_name
 2a. check the tracking of the branches with: git remote show origin

3. use git pull to get the information and merge it into out branch. Or just git fetch(to get the data) and git reset --hard origin/remote_branch_name
to synchronize the working directory and staging area files with the fetched information from the remote repository.
4. A merge request may appear so just write "synchronizing branches" as a commit message, save and exit the editor

Push code to remote
At one point we would like for other developers to see our code and probably to incorporate it inside the main master/development branch on the original repository we cloned. So we can create a pull request. Advice: beforehand pull all the changes from the remote master and merge them with the local branch. Why? In order not to overwrite other's code if in the meantime while we were working someone else made a change to the master branch and now our codebase is older than theirs. So first we do: git pull origin master and then we push our local branch remotely via: git push --set-upstream origin [our_local_branch_name]
To initiate the pull request (requesting the remote server to accept our changes and later merge our code to the main branch(master/develop)) we use: git request-pull [address of remote repository address] [our_local_branch_name]. Of course, you can do the last step using GUI such as GitHub, Bitbucket.

Resolving merge conflicts
While merging branches it is possible for others to have rewritten (made changes) to the same lines of code as you. In order to resolve such conflicts, while making pull request, your favorite editor will appear showing the code with the differences illustrated, so you can choose what to keep and what to discard. Next you will have to create a merge commit by:
git add the conflict files
git commit -m "conflict resolution"
git push will push the resolved (non-conflicting) version of the code so you can restart the pull request successfully.

Keep in mind that when dealing with remote branches if we introduce mistakes to a remote branch we can use git revert. It will create an additional new commit, which will redo our last commit.

Some more practical tips on working locally with GIT:

Undo changes before a commit is made
If we made changes on a wrong branch, and would like to apply them to a different branch. We can save our current project state temporary, just like using copy&paste to another file, with git stash. This will remove all the files from staging. Later we can toggle to a branch (git checkout branch_name) or create a new (git branch branch_name) and to apply the stashed changes we can use: stash apply. If we would like to see which stash to apply we can use: git stash list.

Undo changes after a commit is made
This time we would be working with the repository HEAD pointer. First we will get the last commit hash we are interested in with: git log for later use. Next we will clean up the branch, reverting it to its previous commit (working dir, stage and local repository...) with git reset --hard HEAD^. Now is time to create and checkout/switch to a preferred different branch: git branch, git checkout branch_name (because the HEAD pointer will be detached). When on the branch, we will point the local_dir, staging as well as repository files to the commit we are interested in with (taken from git log): git reset --hard hash of commit 

alternative:

# Create a backup of master branch
git branch backup_master

# Point master to '56e05fce' and
# make working directory the same with '56e05fce'
git reset --hard 56e05fce

# Point master back to 'backup_master' and
# leave working directory the same with '56e05fce'.
git reset --soft backup_master

# Now working directory is the same '56e05fce' and
# master points to the original revision. Then we create a commit.
git commit -a -m "Revert to 56e05fce"

# Delete unused branch
git branch -d backup_master
 

Forgetting to add files to a commit

just add them with: git add file.txt and then use: git commit --amend --no-edit

 

Examples of git reset + HEAD pointer ~1

git reset --soft

- combine several commits into one:

1) reset just the head pointer:  git reset --soft HEAD~3 

2) since all the changed files are in stage, we are ready to make an unifying commit

- reverse just the last commit command made (without touching stage and local files) with: git reset --soft HEAD~1

git reset --hard

- reset the entire project to previous commit state: git reset --hard

git reset --mixed (the default mode)

- undo a previous commit we can use:

git reset HEAD^ - if it is still not pushed to a remote repository

git revert HEAD^ - if it is pushed, and is public, in order to revert it, by creating a new(reverted) commit.

- unstage and uncommit, but keep the local file changes for editing

- create multiple commits from one, little by little with git add and git commit.

When to use cherry picking?

For example if you have fixed a bug in a branch or master and would like to apply this commit to another branch, you just cherry-pick the particular commit and apply it where you would like it.

 

Also good use cases of git, when to use:

rebase - to update local branch with master changes
merge - to merge local changes into master

 

Forgot to create new branch and already made changes?

just create new branch with git switch -c new_branch_name

then commit the changes there.


Congratulations and enjoy the course !

Subscribe To My Channel for updates

Burnout or toxic culture ?

Outsourcing companies are hell to be in for an experienced programmer, because managers are being allowed to mistakes, which are covered, th...