Sometimes, in between projects, I lose track of all the Git tips I’ve learned. Here are some of my faves.
master
branchTired of seeing master
all over your projects? As Scott Hanselman suggests, here’s a one-time fix to change the term to main
(or latest
, or whatever):
$ git config --global init.defaultBranch main
Check his article for details on amending projects in progress.
Here’s the standard:
$ git init
$ touch .gitignore
$ git add .
$ git commit
(Since I edit in vim, I’ll also add *.swp
to .gitignore
right off the bat.)
Next, make a new repository on Github, grab the generated address and:
$ git remote add origin ADDRESS
$ git push -u origin main
If you’re ready to start versioning, you can.
$ git tag -a v0.1.0
$ git push origin --tags
There’s instructions for setting up a tag as a Github release later in this post.
One feature that makes Git so powerful is branching – the ability to put down our work on one feature & pick up work on another without hassle.
For example, we’re writing a new post for our nifty tech blog, and we come across a typo in an old post. By checking out a new Git branch, we can put our writing on hold to fix the typo & push a quick update without pushing our unfinished post. This gets even handier when the features in question impact multiple (or overlapping!) files. Essentially, this is the Git feature which facilitates teamwork best, and it’s handy on your own too. What does this look like in practice?
Let’s illustrate a typical workflow. Say we have a stable project established on main
and we want to work on a new (possibly build-breaking) feature. First, check out a new branch.
$ git checkout -b new-feature
We can see we’re now on the new-feature
branch - any commits will be recorded here instead of on main
.
$ git branch
main
* new-feature
After making some commits and successfully testing our new feature, we can add it to our main
project.
$ git checkout main
$ git merge new-feature
If we’re testing a new Github Pages site addition, or we’re collaborating with others, we can push new-feature
to a new remote branch:
$ git checkout new-feature
$ git push
To also set new-feature
to track its remote counterpart,
$ git push -u origin
(This ensures our local new-feature
is updated with colleagues’ pushes whenever we pull/fetch from remote
.)
Once we’ve merged our changes with main
and we’re all done with the development branch, we can delete it.
$ git branch -d new-feature
To delete a remote branch,
$ git push origin --delete new-feature
To summarize the workflow:
main
branchmain
The preceding workflow is also the basic process for contributing to open-source projects on Github, with a few adjustments:
main
, push the development branch.Of course, that’s just the beginning, so maybe don’t delete your local branch quite yet. The project owner or community may suggest additional changes to you before agreeing to merge your feature.
In Git, we use tags to flag notable commits in a project. Use git tag
to check existing tags on a project. There are two different kinds of tags.
Lightweight tags (git tag TAGNAME
) just label a specific commit. From the Git website,
“[They are] basically the commit checksum stored in a file — no other information is kept.”
Annotated tags store a bit more info. It sounds like they’re the most useful for versioning on Github. To declare a new version using a tag:
$ git tag -a v1.4 -m "version 1.4"
This adds the tag to the most recent commit (of the branch you’re working on locally). If you want to declare something a few commits ago to be a version, use:
$ git log --oneline
f6face4 (HEAD -> main, tag: v0.0.1, origin/main) Commit license.
$ git tag -a v1.4 f6face4
To push a new release, normally we’ll push our commits to main
as well, to advertise our new release on our project’s main page:
$ git push
Either way, we push our commits to the new version’s tag:
$ git push origin v1.4
or, if you like typing the same thing every time,
$ git push origin --tags
This will update any and all tags you’ve fiddled with though, including lightweight tags. To update annotated tags only, use
$ git push origin --follow-tags`
To display your version as a release:
v
and see them all!)Your new version will be displayed on your repository’s main page in the righthand panel under Releases, or at the bottom of the main page, after the README. Github auto-generates .zip
/.tar.gz
distributions of each release version, downloadable from the releases page.
These commands help me observe my git “surroundings”:
git tag
lists all the tag names on your project.
$ git tag
v0.0.1
v0.1.0
v0.1.1
git branch -avv
lists remote & local branches, and what they track.
$ git branch -avv
main c2f592e [origin/main] Minor adjustments.
* new-feature c2f592e Minor adjustments.
remote c2f592e Minor adjustments.
remotes/origin/gh-pages 8003501 jekyll build from Action c2f592e...
git log --oneline
lists your commits with tags & origin labeled.
$ git log --oneline
237406c (HEAD -> main, origin/main) Rearrange README contents.
002cae5 Add info on releasing versions to Github.
36e18ad (tag: v0.1.1) Change faulty code block in README.
758c7ef (tag: v0.1.0) Update changelog.
2832746 Commit changelog.
fc718b4 Commit .gitignore.
1623d3c Commit a readme.
f6face4 (tag: v0.0.1) Commit license.
git describe
shows where you are with respect to most recent tag, in the form V-N-H
, where V
is the most recent version/tag name, N
is the number of commits since then, and H
is the last commit’s hash ID. Like this:
$ git describe
v0.1.1-2-g237406c
git status
shows which files have been changed since last commit.
$ git status
On branch main
Your branch is up to date with 'origin/main'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: README.md
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: README.md
git diff
shows line-by-line details of those changes.
$ git diff
diff --git a/README.md b/README.md
index 190ea13..a75d153 100644
--- a/README.md
+++ b/README.md
@@ -1,15 +1,15 @@
# Learning How Git Versioning Works
-Use `git tag` to check existing tags on a project.
+In Git, we use tags to flag notable commits in a project. Use `git tag` to check existing tags on a project. There are two different kinds of tags.
-Lightweight tags (`git tag TAGNAME`) just label a specific commit. They are
->"basically the commit checksum stored in a file — no other information is kept."
+Lightweight tags (`git tag TAGNAME`) just label a specific commit. From the [Git website](https://git-scm.com/book/en/v2/Git-Basics-Tagging),
+>"[They are] basically the commit checksum stored in a file — no other information is kept."
-Annotated tags sound like they're the most useful for versioning with github.
+Annotated tags store a bit more info. It sounds like they're the most useful for versioning with github. To declare a new version using a tag, do:
To edit the most recent commit message before pushing:
$ git commit --amend
However, this adds our unstaged changes to the commit as well. More generally, we can “tidy up” small local commits (typos, etc.) by refactoring them before pushing. To rewind the last N commits,
$ git reset --soft HEAD~N
After soft resetting, our commit messages are deleted but all our changes remain, unstaged. From here, we can recommit them all at once,
$ git commit -a
or we can add files manually and re-commit them in whatever grouping makes sense to us.
$ git add FILE1
$ git commit -m "FILE-SPECIFIC MESSAGE"
$ git add FILE2 FILE3
$ git commit -m "ANOTHER MESSAGE"
To move a tag to the most recent commit:
$ git push origin :refs/tags/TAGNAME
$ git tag --force -a TAGNAME
$ git push origin main --tags
One last tidbit — please be careful with this one! Unlike other Git commands, reset --hard
deletes changes for good. However, if we’ve made a mess of our project files and just want to start fresh, we can.
$ git reset --hard HEAD
This discards all changes since the last commit (or whichever commit HEAD
is on), including changes staged for commit AND unadded changes.
And that’s it for now! Thanks for reading. :)