Working with Git
Working on a team project has gotten me a lot more familiar with git, having to create multiple branches for different features, pushing to the remote repository, and merging branches into one another.
Let’s take a look at a few commands in a fresh Clojure project!
> lein new speclj bowling-game
> cd bowling-game
git init
git init
will initialize your git repository.
> git init
hint: Using 'master' as the name for the initial branch. This default branch name
...
Initialized empty Git repository in /Projects/bowling-game/.git/
Now we have a new local git repository for our Bowling Game project!
git status
git status
is probably my most used command. This tells me where I’m
at currently in my local git session. Let’s see what this gives us after
we’ve just run git init
.
> git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
README.md
project.clj
spec/
src/
nothing added to commit but untracked files present (use "git add" to track)
At the top, we see we are on the master branch and a bit below that we have some files that haven’t been staged for committed yet.
git add
Since we’ve just created this repository, let’s go ahead and stage these
files for a commit. As shown in the git status
output, you can stage one
file at a time with git add <file>...
.
> git add README.md
> git add project.clj
> git add src/bowling_game/core.clj
> git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
new file: project.clj
new file: src/bowling_game/core.clj
Untracked files:
(use "git add <file>..." to include in what will be committed)
.gitignore
spec/
At this point, we could “commit” our staged files, and only those three
files would be saved to master branch. But since this is our first commit,
we want to commit all of our files. While we could use the git add <file>...
command, there’s a much quicker way to stage all your untracked files: git add .
.
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: .gitignore
new file: README.md
new file: project.clj
new file: spec/bowling_game/core_spec.clj
new file: src/bowling_game/core.clj
git commit
Now that all our files are staged, we’re ready to commit! The easiest way
to commit is to run git commit -m <commit message>
.
> git commit -m "First commit"
[master (root-commit) 131d6ff] Initial commit
5 files changed, 36 insertions(+)
create mode 100644 .gitignore
create mode 100644 README.md
create mode 100644 project.clj
create mode 100644 spec/bowling_game/core_spec.clj
create mode 100644 src/bowling_game/core.clj
If you check your git status, you’ll see that there’s nothing to commit.
All changes have been saved in your git repository on the master
branch.
> git status
On branch master
nothing to commit, working tree clean
Now, occasionally you may accidentally type git commit
without the -m
argument. This will put you in the vim
editor, and if you’re as unfamiliar
with it as I am, you may get a little lost. So here’s what you can do if you
encounter this scenario.
> git commit
# Please enter the commit message for your changes. Lines starting
# ... more comments ...
Press the I
key to start typing, then type your commit message.
First commit
# Please enter the commit message for your changes. Lines starting
# ...
After you’ve finished typing your commit message, go ahead and press ESC
,
type :wq
, and press ENTER
. After that, you should see the commit
output in your console!
Branching Out
There are plenty of reasons to have different branches in your git repository. You may be working with several other people, or maybe you have a few different features that you want to keep separated until complete. Whatever your reason, here are some ways you can create branches.
> git checkout -b feature/spare
Switched to a new branch 'feature/spare'
git checkout -b <branch>
will create and switch to a new branch.
If we enter git branch
, we can see all available branches and which one
we currently have checked out indicated by the asterisk.
> git branch
* feature/spare
master
If we check our git status
, we can see we are indeed on feature/spare
and that the branch is clean (nothing modified from the last commit).
On branch feature/spare
nothing to commit, working tree clean
Go ahead and modify a couple files. You could just add a comment anywhere
in spec/bowling_game/core_spec.clj
and src/bowling_game/core.clj
.
; Updated from feature/spare
Now if we check our git status, we will see those changes being tracked.
git status
On branch feature/spare
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: spec/bowling_game/core_spec.clj
modified: src/bowling_game/core.clj
no changes added to commit (use "git add" and/or "git commit -a")
git stash
Now I need to go back to master
for something, but I’m not quite ready
to commit my changes. I really don’t want to lose all the work I put
into this branch, so I need a way to save the changes without committing them.
Well, git stash
will do exactly that!
> git stash
Saved working directory and index state WIP on spare: 131d6ff Initial commit
If I enter git stash list
, I can see my stash is saved in stash@{0}
.
> git stash list
stash@{0}: WIP on spare: 131d6ff Initial commit
All your stashes are saved in a stack-like list. So the latest stash will
always be saved in stash@{0}
while older stashes will be toward the bottom
of the list.
git stash apply
I actually don’t need to go to master anymore, so I’ll need to reapply the changes I just stashed. There are a few different ways to do this.
git stash apply stash@{N}
, where N is the stash number, will apply the
specified stash to the current branch.
> git stash list
stash@{0}: ...
stash@{1}: ...
stash@{2}: ...
stash@{3}: WIP on spare: 131d6ff Initial commit
> git stash apply stash@{2}
On branch feature/spare
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: spec/bowling_game/core_spec.clj
modified: src/bowling_game/core.clj
no changes added to commit (use "git add" and/or "git commit -a")
A couple other ways to apply stashes:
git stash apply
- This is synonymous to
git stash apply stash@{0}
- This is synonymous to
git stash pop
- This will apply changes from
stash@{0}
and then delete that stash
- This will apply changes from
git switch
Okay, now I actually do want to go to master
. Let’s go ahead and
commit our changes to feature/spare
and switch over to master
.
This is actually a pretty simple command. Just type
git switch <branch>
–Not too complicated.
> git add .
> git commit -m "Implement spare"
[feature/spare 8192308] Implement spare
2 files changed, 2 insertions(+), 2 deletions(-)
> git switch master
Switched to branch 'master'
Now if you go to your core.clj
and core_spec.clj
files, you will see
that your changes are no longer there. All those changes were left
in your feature/spare
branch.
If you want to bring those changes back over to master
, you can enter
git merge feature/spare
and you’ll see those changes come back on the master
branch!
There’s still tons of other commands and options that you could go through with git, but these are just a few that I’ve found most useful over the past few days.