cd git-daily-basis touch file.txt git init
git remote add origin email@example.com:ledahu05/git-daily-basis.git
To check the link
git remote -v origin firstname.lastname@example.org:ledahu05/git-daily-basis.git (fetch) origin email@example.com:ledahu05/git-daily-basis.git (push)
Clone a repository
cd ~/working git clone firstname.lastname@example.org:ledahu05/git-daily-basis.git ls git-daily-basis
Make a change, commit and push
echo 'console.log("test")' >> file.txt git add -A file.txt git commit -m 'add debug statement' git push
Get data from remote
This command is actually a shortcut of two commands:
git fetch git merge
Branch and checkout
Let's create a new branch called new-feature:
git branch new-feature
To see all our branches:
We are still currently on the master branch, therefore all commit will be store on the master branch. To switch to the new-feature branch:
git checkout new-feature touch new-feature.txt git add -A git commit -m "Add new feature"
If we checkout the master branch by running git checkout master, there will be no new-feature.txt:
git checkout master ls //no new-feature.txt
To create a branch a check it out directly :
git checkout -b new-feature-2
To switch to the branch we checked out last:
git checkout - //we are on master git checkout - //we are on new-feature-2
//we are on new-feature-2 echo 'console.log("test from new-feature-2")' >> file.txt touch file2.txt echo 'console.log("this is feature 2")' >> file2.txt
At this point on the branch new-feature-2 there is a modified file and an untracked file.
git add -A git commit -m "add feature 2"
Now we want to merge this branch to the master branch:
git checkout master git merge new-feature-2
Git will figure out what algorithm it will use to merge the branch. The decision is taken in regards on the type of difference between the branches. If the differences are linear enough, git will use the fast forward algorithm.
Now we can push the master branch and remove the new-feature-2 branch:
git push git branch -d url-slugs
Resolving merge conflicts
This can happen when running a git pull if 1/ there are changes on a file both locally and and remotely and 2/ these modifications can't be merged automatically.
Let's make a conflict. In ~/working/git-daily-basis:
Edit file.txt and change echo console.log("test") by echo console.log("test conflict"). Commit and push the change:
git commit -am 'introducing conflict' && git push
Now in ~/git-daily-basis, without pulling the remote repo edit file.txt and change echo console.log("test") by echo console.log("test more conflicts"). Commit the changes and try to push the changes to the remote:
git commit -am "introducing more conflicts" && git push
We get an error from the push command because remote contains changes we don't have locally. To be able to push our changes we first need to pull the changes from the remote. For that we ran
We get an error from the pull command because git is unable to merge automatically the changes from the remote and the local file. We must fix the conflict and commit the result.
git status //will tell us what files are in conflicts, aka file.txt
We need to open the file file.txt:
<<<<<<< HEAD echo console.log("test more conflicts") ======= console.log('test conflicts') >>>>>>> 4c897c840eac7251e78f4dfa03f3a8ac7d036db2
The code between <<<<<<<HEAD and ======== are the local change and the code between ======= and >>>>>>>> are the remote changes. 4c897c840eac7251e78f4dfa03f3a8ac7d036db2 is a commit id. Now we need to decide what code should stay and what code should be removed. We must remove all markers:
echo console.log("test more conflicts, resolved")
Now we can stagged and commit as normal:
git add -A git commit -m "test more conflicts" git push
Branch and stashing
The need may occur for stashing changes in the following use case for example. I'm working a new branch because I've been asked to develop a new feature:
git branch -b new-feature-4 touch file4.txt echo "console.log('feature4'" >> file.4.txt
At this point, I got a call to tell me there is a critical bug on production. To fix the bug we need to create a new branch. The idea is that I want to create a new branch without having to commit the new changes i've just made (because the code still contain errors for example but there is emergency). The solution here is to stash the changes
git add -A git stash
The changes are saved but the head is back to the last commit:
ls //no file4.txt
Now I can create safely a new branch to fix the critical bug;
git checkout -b hotfix //fix bug git add -A git commit -m "Fix bug" git checkout master git merge hotfix
To resume the work on the new feature:
git checkout new-feature-4 git stash apply ls //file4.txt is there
The git pager
Git command output are sometimes so big that result are displayed using the pager. By default the less unix command is used for the pager. Here is reminder of some useful command:
git log //output displayed using the pager q to quit the page /a_string_to_search n to go the next search result N to go the previous search result
Using the git history
The git log command will output all the commit starting from the most recent.
git log commit 45cff52b9377fb510f1d53e6d12a8739f1ac21ff (HEAD -> master, origin/master) Merge: bef03c6 4c897c8 Author: ledahu <email@example.com> Date: Tue Mar 17 17:47:12 2020 +0100 .... .... ....
Format the history
Condense the history on a single line with --online
git log --oneline
git log --graph
Display the changes made in each commit with:
git log -p
Display number of insertion and deletion using:
get log --stat
Filter the history
git log -3
will show only the 3 most recents commit
git log --after="yesterday"
will show only the commit that happened between now and yesterday. We could have used "30 minutes ago" or "last tuesday" or "last week" or "2 weeks ago" or "3-15-16" or "3/15/16"
git log --after="yesterday" --before="30 minutes ago"
will show only the commit that happened from yesterday to 30 minutes ago.
git log --author="ledahu05"
will only the commit message from the specified author. We can use regular expression here. git log --author="ledahu05\|cseguino". This command perform a search in the author field of each commit.
git log --grep="hotfix"
will show all commit whose message contains "hotfix"
We can look for a string in the code changes with -S option:
git log -p -S"console"
We can also use regular expression for searching the code changes with -G option:
git log -p -Gconsole\|log
To ignore the case in all our seach just use the -i option
git log --no-merges
will show only commits that are not merges
To show commits that are contained within a range of references: git log master..new-feature will show the commit between the ref master and the ref new-feature. After a merge this command will have no output.
git log file.txt will show only commits related to the specified filename
Composing formating and filtering options
git log -3 -i --author="ledahu05" file.txt
will show the last three commit from ledahu05 (or LEDAHU05...) where file.txt was changed
git log -S"console" --after="yesterday" --oneline --stat
will show all the commit that included the word console in the changes from yesterday to now, and show the result in the condensed form with the number of additions and deletions.
Comparing file changes using git
git diff will show the differences between two references. By default it will use the last commit and the current working directory.
git diff --cached
it will show the differences between the working directory and the staging area
git diff HEAD
it will show all the uncommited changes. It is comparing both the working directory and the staging area with the last commit
Grab the lastest remote branches
And the run
git diff origin/master
It will show all the changes that we have locally that have not been merged to our remote master branch.
git diff file.txt
it will narrow the command to the specified file.
Semantic versionning with git tag
git tag v1.0.0
It will create a tag with the label v1.0.0
It will output all the tags of our repo.
The purpose of a tag is to create a reference to a commit that can be changed.
To push a tag to the remote use
git push --tags
To annotate a tag use
git tag -a v1.0.1 -m 'patch 1'
Fixing commit message
It happens to make a typo in a commit message. If the commit has not yet been push we can do as follow to fix it:
git commit --amend -m "message without typo"
Add files to an existing commit
First add the files to the staging area:
git add -A
Then commit using the --amend option:
git commit --amend -m "adding new files"
Remove a file from the staging area
After adding a file to the staging area and before commit the changes we realize there is a file we don't want to commit. This is how we can proceed:
git reset HEAD filename
Now the file is removed from the staging area. Now we can remove the file safely.
Remove changes from a commit before pushing
To compare what we are going to push with what is on the remote we can perform a diff:
git diff origin/master HEAD
In the output we can figure out some changes we already commited that we don't want to push. We need to find the commit id where we we commited the file. For that purpose we run:
git log --oneline
Once we found the commit id, we can copy the previous commit id where we want to go back and run:
git reset 85db789
Here we used git reset, and we are doing that only because changes have not yet been pushed. Don't use git reset on something you already push since it will change the history.
Now we need to run a git status and add/commit only what we really want to commit/push
Comparing git reset options
To better understand the options, let's modify a file and commit the changes
git add file git commit -m "understanding git reset options"
Let's explore the first option --soft:
git reset --soft HEAD ~1 git status //there is changes to be commited
We are moving the changes from the commited status to the changing area.
git log --oneline //the commit is gone
Let's commit the changes again:
git commit -m "understanding git reset options part 2"
Now let's explore the --mixed option, which is the default option is no option are specified:
git reset --mixed HEAD~1 git status //there is unstaged changes
So the mixed options takes a step further, going from the commit state to the unstage state. Nevertheless, the changes are still in the working directory.
Let's add and commit the file again and try the --hard option:
git add file git commit -m "understanding git option part 3" git reset --hard HEAD~1 git status //nothing, clean. The changes are gone.
The commit is removed, the changes are unstaged and removed from the working directory.
What if we made a reset --hard and realized we lost the changes? there is still a hope:
Pick the commit id where you want to go back, in our example the one with comment "understanding git option part 3" and run:
git reset --hard commit_id
Undo a commit that has already been pushed
git revert commit_id
The history is maintained here, the command will add commit.
How to push a new branch that does not exist remotely
Let's create a new branch:
git checkout -b new-local-branch
To see detailed information about our branches use the -vv flag
git branch -vv master 45cff52 [origin/master] resolving conflicts * new-local-branch 45cff52 resolving conflicts
We can see that new-local-branch is just a local branch for now. Let's add some code and try to push it:
touch 'file.js' echo 'console.log("local branch")' >> file.js git add file.js && git commit -m "add some code" git push
But the push command fail and git tells us new-local-branch does not exist remotely. To fix this:
git push -u origin new-local-branch git branch -vv master 45cff52 [origin/master] resolving conflicts * new-local-branch a6b9362 [origin/new-local-branch] some change
Copy a commit from one branch to another
You want a piece of code from a branch without merging the whole branch.
On the branch containing the piece of code you want, do git log --online and copy the commit_id
Now switch to the branch you want to add the code to and run:
git cherry-pick commit_id
Move a commit that was committed on the wrong branch
Before pushing we realize we commited the code on the master branch instead of the hotfix branch. Here this a cherry-pick scenario on hotfix branch and a git reset scenario on the master branch.
On the master branch get the commit_id that commited the code. Now switch to the hotfix branch and run the cherry-pick command to copy the code:
git checkout -b hotfix git cherry-pick commit_id git push
Ok now the hotfix branch is clean. Now we need to clean the master branch. On the master, get the commit_id we want to target:
git checkout -b master git log --oneline //get the commit_id before the one we used before git reset commit_id
This is a mixed reset to the changes are still in the working area. We can use git checkout filename to revert file.
git status //will give the file we must checkout git checkout file git status //clean.
Save local change before pulling
You are working locally on a file and we realize we didn't pull before starting to code. So we run git pull and it fails because some changes have already been on the same file and these changes has already been pushed. It is a good scenario for stashing our changes.
git stash git pull
Now we need to get our code back.
git stash pop
Eventually we run here in a merge conflict. We edit the file in conflict and make the appropriate changes. Then we add and commit the changes. Finally we can push the changes.
To check the stach has been correctly cleaned:
git stach list //get the stach_id if any git stach drop stach_id
Starting from an old comit
git checkout commit_id
Here we are in a detached mode (HEAD is not pointing to a branch) which is not good if we want to commit new changes from there. To fix this:
git checkout -b exploring-old-commit
Delete a branch after a pull request
The branch delete_branch_after_pull_request has been deleted on github, how to update our local repo ?
git remote prune origin --dry-run git remote prune origin git branch -d delete_branch_after_pull_request
Change the commit message of a previous commit with interactive rebase
First of all, we don't want to change a commit message that has already been pushed because it might have been pulled by someone else. Let's make some changes:
touch file.js echo 'change1' >> file.js && git add file.js && git commit -m "change1" echo 'change2' >> file.js && git add file.js && git commit -m "change2" echo 'change3' >> file.js && git add file.js && git commit -m "change3" git log --oneline //all 3 commits are above origin/master, we can safely change them git rebase -i HEAD~3 pick xxxxxx change1 pick xxxxxx change2 pick xxxxxx change3 //options are: p (pick), r (reword), e (edit), s (squash), f (fixup)
Our goal here is to change the commit message change1, so we will mark it with reword:
reword xxxxxx change1 pick xxxxxx change2 pick xxxxxx change3
After an other text editor open to allow us to edit the commit message "change1", we can set it to "Change 1"
Add a file to a previous commit with rebase
We want to add a file to the "change2" commit.
git rebase -i HEAD~2 pick xxxxxx change2 pick xxxxxx change3 //Edit to: edit xxxxxx change2 pick xxxxxx change3
We are back to the command line but we are in interactive rebase session.
touch interactive-rebase.js && git add interactive-rebase.js git commit --amend --no-edit
We can finish the rebase interactive session:
git rebase --continue
Merge conflicts while changing commits during a rebase session
git rebase -i HEAD~2 pick xxxxxx change2 pick xxxxxx change3 //Edit to: edit xxxxxx change2 pick xxxxxx change3
We are back to the command line but we are in interactive rebase session. Let's make a change to an existing file that will create a merge-conflit.
//edit and save existing-file-with-conflictual-changes.js git commit --amend --no-edit git rebase --continue //MERGE CONFLICT
We are going into a merge conflict during a rebase. As usual edit and clean the file in conflict:
//edit and clean existing-file-with-conflictual-changes.js git add existing-file-with-conflictual-changes.js git commit -m "merge rebase conflicts" git rebase --continue
Squash commits before they are pushed with rebase
Now is time to push, but we don't want to push change1, change2 and change3 as 3 differents commits but instead as a single commit. This is a scenario for rebase & squash.
git rebase -i HEAD~3 pick xxxxxx change1 pick xxxxxx change2 pick xxxxxx change3 //Edit to pick xxxxxx change1 squash xxxxxx change2 squash xxxxxx change3 //after save & exit, we can edit commit message //after save & exit git push
Ignore a file that has already been commited and pushed
touch .ignore //add the secret.js to .gitignore, add, commit and push
But secret.js file was pushed and adding secret.js to .gitignore is not enough here, it's too late. To fix this scenario we must first remove the file from the cache first:
git rm -r --cached . //it will remove all our changes git add -A //add all our changes again git status //will inform our secret.js is deleted git commit -m "secret.js removed" && git push