A couple of months ago, the local Ruby meetup group, BrisRuby, put out a call to see if anyone could do an introductory git talk. It ended up turning into two talks over two months. "Gitting Into Version Control: an introduction to git" and "Gitting Out Of Trouble: what to do when things go wrong".
I've written up the content in this blog post, and the slides are linked below.
Gitting Into Version Control
Why use version control?
- It keeps a change history of every file
- Branches let you, or several people, work on things concurrently
- Auditing - where features were introduced, who worked on what
Why git?
- Used by popular code hosting services like Gitlab, Github and Bitbucket
- Creates a full copy of the whole repository (unlike SVN)
- Open source
- Powerful features
Initialise a repository:
$ git init --bare <directory>
Initialise a shared repository with --bare so that it doesn't create a working tree.
Clone an existing repository:
$ git clone <URL>
Edit the config:
$ git config --global user.name "Charelle Collett" $ git config --global user.email "charcol@example.com" $ git config --global --edit
Remove --global to change settings for a single project.
See what changes will be applied:
$ git status
Add files to commit:
$ git add <filename>
Or you can use -a while committing
Commit your changes:
$ git commit -m "message"
See the history:
$ git log
Move to a different branch:
$ git checkout <name-of-branch>
Create a new branch and move to it:
$ git checkout -b <name-of-branch>
Which is the same as:
$ git branch <name-of-branch> $ git checkout <name-of-branch>
Show connections to other repositories:
$ git remote -v
Pull from a certain remote:
$ git pull <remote>
Push to a specific branch:
$ git push <remote> <branch>
Add a remote:
$ git remote add <name> <url>
Only push to a bare repository!
Remove a remote:
$ git remote rm <name>
Add branch config to .git/config:
$ git config --edit
[branch "new-feature"] remote = origin merge = refs/heads/new-feature
More info:
Git documentation:
https://git-scm.com/book/en/v1/Getting-Started
Atlassian's git tutorial:
https://www.atlassian.com/git/tutorials
Github / Code school interactive tutorial:
https://try.github.io/levels/1/challenges/1
Codecademy interactive tutorial:
Gitting Out Of Trouble
There are many different ways to do the things mentioned here.
Rename a branch:
$ git branch -m <oldname> <newname>
Reverting uncommitted changes:
$ git checkout <file> $ git reset --hard
Delete a branch:
$ git checkout master $ git branch -D <branch>
If you have pushed:
$ git push --delete <branch> $ git fetch --prune $ git branch -D <branch>
Changing a commit message for the most recent commit:
$ git commit --amend
If you have pushed:
git push --force-with-lease
CAUTION: --force rewrites history
To change an older commit, you must rebase.
To delete a commit:
$ git rebase -i <previous-commit>
Then delete the line you want to remove.
If you have pushed:
$ git revert <commit> $ git push
revert creates a new commit that undoes the changes
If you have committed to the wrong branch:
$ git branch <new-branch> $ git reset --hard <commit>
If you have pushed:
$ git revert <commit> $ git push $ git checkout <correct-branch> $ git cherry-pick <commit>
To squash commits / rewrite history / edit old commits / reword messages:
$ git rebase -i <commit>
or for the four most recent commits:
$ git rebase -i HEAD~4
Commits are shown oldest to newest. pick the oldest, and squash the newer commits. You can also reorder commits.
If you have pushed:
$ git push --force-with-lease
To get the latest changes and rebase onto those changes:
$ git checkout master $ git pull $ git checkout <branch> $ git rebase master
If you have issues, you may want to rebase -i (interactive)
If there are conflicts and you need to manually merge, search for >>>> to find the conflicts.
Add the fixed files (git add <file>) then git rebase --continue. It's also possible to git rebase --abort
Reference log shows when the HEAD has been updated in the local repository:
$ git reflog [--all]
Stash changes:
$ git stash
Files need to be tracked before stashing. (git add . ) Or you can --include-untracked
Retrieve changes and remove them from the stash:
$ git stash pop
Remove from the stash:
$ git stash drop
Retrieve changes but keep them in the stash:
$ git stash apply
Small glossary
origin: default name for the repository you cloned from
working tree: where you edit the checked out branch (can have multiple)
clean working tree: current files you are editing match HEAD
bare repository: repository without a working tree. Pushing to a non bare repo can cause conflicts
staging: changes to be committed
HEAD: is the commit at the tip of the current branch
revert: creates a new commit to undo changes
reset: changes which commit HEAD is pointing to
Other interesting things
patch: Export changes as a patch that can be applied later
.gitignore: List of files that git should ignore
diff: See differences between commits
blame: See who was responsible for changes
More lessons on presenting
- Even if you've increased the text size, someone will want it larger.
- Even if HDMI works with your laptop on several different projectors, it won't always work on the one you're using ><
- Even if a mini-DP adapter doesn't work on other projectors, it may work on the one you're using
The discussion afterwards is always my favourite part, because it's a chance to learn from other people. From this I found out that a colleague never uses git pull but instead fetch then rebase (since pull is a fetch then merge, this avoids the merge). You can find more detail in this excellent blog post: git: fetch and merge, don’t pull | Mark's Blog
Hopefully this is useful! Someone at the Ruby meetup suggested a potential future talk about different git workflows and branching models, but I don't think I have enough experience in different teams. Perhaps someone else would like to research and give this talk?