Using SSH Over HTTPS: Instructions
Using SSH Over HTTPS: Instructions
When you push or pull code from GitHub, it's essential that GitHub can successfully authenticate you
before letting you run these commands. This means that every time you try to git push or git
pull, GitHub will ask you for your email and password, and if they are correct the command will
execute. Without authentication, GitHub would be chaos: anyone could push whatever code they
wanted to any repository at any time!
So, being able to authenticate people when they push or pull is critical. But it also gets tedious pretty
quickly. When you are pushing and pulling frequently, typing your credentials each time is bit of a
hassle. Thankfully, if you use the SSH protocol and configure everything properly, you will be able to
authenticate without having to put your username and password each time. To do this we need to create
an SSH key locally, add it to GitHub, and make sure we can authenticate successfully.
ntroduction
As you get more comfortable adding and committing changes using git, you may sometimes
accidentally commit something you didn't mean to, or you may want to remove some file that's in the
working directory before it's been staged. We'll show you some techniques to undo your changes in this
chapter. Please be warned that some of these commands are not reversible, so use them with caution!
checkout
If you want to remove files from the working directory (before they have been staged) you can use git
checkout NAME_OF_FILE. Be careful with this - you can not undo this command!
Here's a quick example. Create a new git repository, then add and commit a blank file called
first.txt. Once you've committed the file, echo hello > first.txt to add some text to the
file. If you check git status now, you'll see that first.txt is not staged for commit. If you
decide that you don't like the change you just made to the file, you can type git checkout --
first.txt. If you cat first.txt you'll see the file is empty again!
clean
If you are dealing with an untracked or unmerged file, you cannot use git checkout to remove it
from the working directory. You must use git clean -df to remove these files. Be careful with
this - you can not undo this command either! (Curious about the -df flags? Run man git-clean to
learn more about this command!)
git rm --cached
We've seen what to do if we have something in the working directory that we want to remove. But what
if we accidentally add something to the staging area and want to move it back to the working directory?
To do this, you can type git rm --cached NAME_OF_FILE. If you need to remove a folder pass
the -r flag to git rm --cached. If you want to move all of your files in the staging area to the
working area you can type git rm -r --cached .. If you want remove your files from the
staging area AND the working directory, you can type git reset --hard HEAD, but be careful -
this can not be undone!
git reset --mixed COMMIT_SHA - moves the files committed back to the working directory (if
you use git reset without a flag, the default will be --mixed)
What's the COMMIT_SHA, you ask? You may have noticed that every commit has a unique identifier,
called a sha, which identifies that commit. If you type git log --oneline, you'll see your list of
commit messages along with the first seven characters of the commit sha. This is what you should pass
into each of these commands.
Using reset will not change the commit that you switch to but any commits that have come after it.
So if we have 4 commits:
a808698 Fourth commit
ca0bbb4 Third commit
5ffcac5 Second commit
ac49968 First commit
And I want to move the last two commits to the staging area:
git reset --soft 5ffcac5, this will move whatever files we had in the Fourth commit and
Third commit back to the staging area.
Your Turn
1. Create a folder called destruction.
2. cd into that folder.
3. Initialize an empty git repository.
4. Create a file called done.txt.
5. Remove that file from the working directory (remember you can not use git checkout).
6. Create a file called stage_me.txt.
7. Add stage_me.txt file to the staging area.
8. Move stage_me.txt file from the staging area to the working directory.
9. Add stage_me.txt file to the staging area.
10.Remove stage_me.txt from the staging area and the working directory.
11.Create a new file called commit_me.txt.
12.Add commit_me.txt to the staging area.
13.Commit with the message "adding commit_me.txt".
14.Create another file called second.txt.
15.Add second.txt to the staging area.
16.Commit with the message "adding second.txt".
17.Check out your previous commits using git log --oneline to see the unique identifier or
SHA for each of your commits.
18.Using git reset, undo the previous commit and move your changes back to the working
directory.
19.Add second.txt again.
20.Commit with the message "Trying to commit again".
21.Using git reset undo the previous commit and move your changes back to the staging
area.
22.Commit with the message "Trying to commit again and again".
23.Using git reset undo the previous commit so that any changes are not part of the working
directory.
24.Pat yourself on the back! You just went through a pretty complex git workflow!
Well done! Play around some more with these commands as they will be essential when dealing with
larger files, branches, and merges.
Branching
So far in our Git workflow we've only been working on a single branch. But when you're working with
a team, this isn't usually desirable. What if you want to go off on your own and work on some
experimental new feature? It would be nice if you could do so without worrying about breaking the
code for everyone else, or conflicting with things that other people are working on.
In most modern work flows, we do not do all of our work on a single branch. Instead, we usually have
many different branches for certain use cases (bug fixes, new features, deployment), so it's essential to
understand how to create, delete, and merge branches.
Before creating a branch, let's first type git branch in the terminal. You should see a list of all your
branches; right now, there should just be a single branch called master. This is the default branch for
all Git repositories.
To create a new branch we use the git checkout command with the -b flag and then pass in a
name of a branch. This looks like git checkout -b NAME_OF_BRANCH.
If we want to move to another branch that has been previously created we use the git checkout
command and then specify the name of a branch. This looks like git checkout
NAME_OF_BRANCH
To delete a branch we make sure we are not on that branch and then run git branch -D
NAME_OF_BRANCH
To see all of the branches we have, we can type git branch -a. The -a flag will include remote
branches (branches on GitHub or other remote locations). The flag does not matter right now, but it's
good to get in the habit of using it with the git branch command.
Try creating a branch called second branch. When you type git branch -a, you should now see
two branches; your current branch will have an asterisk next to it. You can now add and commit files to
the two branches completely independently of one another! Try this out by adding separate files to each
branch.
Merging
With a branch workflow, we usually create a new branch for something we are working on (a new
feature, a redesign, etc.). When we are done with that modification, we need to put our code back on
the master branch. Traditionally, the master branch is reserved for production code and immediate
bug fixes. In order to put our code back on the master branch we need to merge our code in. Here's
what that looks like:
Let's:
1. Create a folder called learn_branching and cd into it => mkdir learn_branching
&& cd learn_branching.
2. Initialize a git repository => git init.
3. Create a file called first.txt => touch first.txt.
4. Add that file git add ..
5. Commit that file git commit -m "initial commit".
6. Create a new branch called feature => git checkout -b feature.
7. Now that you are on the feature branch, create a file called new.txt => touch
new.txt.
8. Add that file => git add ..
9. Commit that file => git commit -m "adding new.txt".
10.Create another file called another.txt => touch another.txt.
11.Add that file => git add ..
12.Commit that file => git commit -m "adding another.txt".
13.Change back to the master branch => git checkout master. Note that this branch has no
awareness of new.txt or another.txt!
14.Merge our changes from the feature branch into the master branch => git merge
feature
15.Delete our branch called feature => git branch -D feature
Now if you take a look at git log --oneline --decorate you'll see that the commit history
on feature has ben merged into master! (--decorate gives you nice coloring around branches and
where they are in the commit history.)
Your Turn
Practice makes perfect. Walk through the following steps to get more experience with the branching
and merging workflow.
1. Create a folder called branch_time.
2. cd into that folder.
3. Initialize an empty git repository.
4. Create a file called first.txt, then add and commit the file.
5. Create a new branch called amazing_feature.
6. Create a file called best.txt.
7. Add the file.
8. Commit the file with the message -m "added best.txt".
9. Switch back to the master branch.
10.Merge your changes from the feature branch into master.
11.Delete the feature branch.
As you work on a project by adding and modifying files and committing changes, your commit history
will expand and your git log will grow. Sometimes you'll want to compare the history of your code
at two different points in time. To do this, we can use the git diff command.
If you want to see differences between your commits you can use the git diff command and
specify the SHA to compare. This will compare your code now to your code at that SHA. Here are a few
different kinds of diff-s that you can see.
git diff - See changes in the working tree not yet staged for the next commit.
git diff --cached - See Changes between the staging area and your last commit.
git diff HEAD - See all changes in the working directory since your last commit.
git diff ANOTHER_BRANCH - compare with the latest code on another branch
git diff HEAD~1 HEAD - compare with the previous commit (add ~2, ~3 for older commits)
Try this out with one of your earlier examples, or create a repository from scratch. Build up a commit
history of five or so commits, then explore these different ways to compare differences with git
diff. It's best if you modify files between commits rather than simply adding or removing files, so
that you can begin to appreciate git diff in its full glory!
Things get even worse when you commit changes to the same file on two different branches. In that
case, Git does not know which commit to go with so it creates a merge conflict. This is basically Git's
way of saying "Hey human, you're asking me to put conflicting files in the commit history; I don't
know how to resolve these conflicts, so you take care of it and let me know when you're done."
Let's see an example by creating our very own merge conflict! Starting in our home directory:
Stashing
Sometimes you are working with certain files and do not want to add and commit them, but you do not
want to discard them either. For example, maybe you're right in the middle of working on some feature
when a huge update gets pushed to your remote upstream, and you need to pull the changes in right
away to be sure that the code you're writing still works.
When you try to pull or merge code and you have changes in your working directory, git won't let
the pull or merge to go through. In other words, you can't merge code into the branch you're
working on unless your working directory is clean. So, what should you do if you're working
directory isn't clean, but you aren't ready to commit yet? This is a perfect example of where
stashing can help. You can think of stashing as a temporary way of remembering changes without
making an official commit.
Here are the commands you can using when stashing:
You can also use git stash pop/apply stash@{number} to retrieve a specific stashed
change.
Stashing is quite useful when you are not ready to commit something, but need a clean working
directory. You can learn more about git stash here and here.
Stashing
Sometimes you are working with certain files and do not want to add and commit them, but you do not
want to discard them either. For example, maybe you're right in the middle of working on some feature
when a huge update gets pushed to your remote upstream, and you need to pull the changes in right
away to be sure that the code you're writing still works.
When you try to pull or merge code and you have changes in your working directory, git won't let
the pull or merge to go through. In other words, you can't merge code into the branch you're
working on unless your working directory is clean. So, what should you do if you're working
directory isn't clean, but you aren't ready to commit yet? This is a perfect example of where
stashing can help. You can think of stashing as a temporary way of remembering changes without
making an official commit.
Here are the commands you can using when stashing:
You can also use git stash pop/apply stash@{number} to retrieve a specific stashed
change.
Stashing is quite useful when you are not ready to commit something, but need a clean working
directory. You can learn more about git stash here and here.
Pre-reading
Before we dive deep into rebasing, start by reading this excellent tutorial on Atlassian. Then answer the
following questions:
• What does it mean when we say merging can "pollute" our commit history?
• How does rebasing solve the problem of not needing an extra commit?
• What is the "Golden Rule" of rebasing? Why is knowing this so important?
Let's start with a project, add a few commits and then explore the command git rebase -i:
Rebase with GitHub
Once you have rebased, if you try to push to GitHub, your push will be rejected because the remote
branch has a different commit history. In order to bypass this, you can use the --force (or -f) flag
after git push, but be very careful - this will override your GitHub commit history. You never want
to do this if other people are working on that remote branch. This is only useful if you are alone and
want to push up your commits before merging into a branch that others work on. You can learn more
about rebasing here.
Revert
The git revert command undoes a commit, but unlike git reset, which removes the commit
from the commit history, it appends a new commit with the resulting content. This prevents Git from
losing history, which is important for the integrity of your revision history and for reliable
collaboration. When you are working on a repository with other developers, using git reset is
highly dangerous because you alter the history of commits which makes it very difficult to maintain a
consistent history of commits with other developers.
Let's imagine the following situation.
1. You are working on a file and you add and commit your changes
2. You then work on a few other things, and make some more commits
3. Now you realize, three or four commits ago, you did something that you would like to undo -
how can you do this?
You might be thinking, just use git reset, but this will remove all of the commits after the one you
would like to change - git revert to the rescue! Let's walk through an example:
Git reflog
Finally, if you make a change like undoing a commit using git reset, or have reverted, or squashed
and you want to undo that change, You can type git reflog and you will see previous changes you
have made with unique SHAs. You can git reset --hard SHA to go back to a previous state. To
see this in action, try rebasing the example above to squash the last two commits into one. Then take a
look at the history you get back when you type git reflog.