List of contents
- –set-upstream
- How to undo last commit in Git?
- How would you skip a git hook?
- Save uncommitted changes with git stash
- Navigate git command pager output with Unix less command
- View commit history with git log
- Compare file changes with git diff
- Show who changed a line last with git blame
- Use semantic versioning with git tag
- Clean up commits with git rebase
- Diagnose which commit broke something with git bisect
- Run scripts on git events with git hooks
- Configure global settings with git config
- Remove unnecessary git tracking with .gitignore file
- Remove all unnecessary git tracking with a global .gitignore file
–set-upstream
git branch --set-upstream <remote-branch>
sets the default remote branch for the current local branch.
Any future git pull command (with the current local branch checked-out),
will attempt to bring in commits from the
One way to avoid having to explicitly do –set-upstream is to use the shorthand flag -u along-with the very first git push as follows
git push -u origin local-branch
This sets the upstream association for any future push/pull attempts automatically. For more details, checkout this detailed explanation about upstream branches and tracking.
To avoid confusion, recent versions of git deprecate this somewhat ambiguous --set-upstream option in favor of a more verbose --set-upstream-to option with identical syntax and behavior git branch --set-upstream-to <remote-branch>.
Rules are different for git push and git pull.
How to undo last commit in Git?
1 | $ git commit -m "Something terribly misguided" (1) |
- This is what you want to undo
- This leaves your working tree (the state of your files on disk) unchanged but undoes the commit and leaves the changes you committed unstaged (so they’ll appear as “Changes not staged for commit” in git status and you’ll need to add them again before committing). If you only want to add more changes to the previous commit, or change the commit message1, you could use git reset –soft HEAD~ instead, which is like git reset HEAD~ but leaves your existing changes staged.
- Make corrections to working tree files.
- git add whatever you want to include in your new commit.
- Commit the changes, reusing the old commit message. reset copied the old head to .git/ORIG_HEAD; commit with -c ORIG_HEAD will open an editor, which initially contains the log message from the old commit and allows you to edit it. If you do not need to edit the message, you could use the -C option instead.
Note, however, that you don’t need to reset to an earlier commit if you just made a mistake in your commit message. The easier option is to git reset (to unstage any changes you’ve made since) and then git commit --amend, which will open your default commit message editor pre-populated with the last commit message.
Beware however that if you have added any new changes to the index, using commit –amend will add them to your previous commit.
Reference link here from stackoverflow and here from git.
How would you skip a git hook?
I have found some scenerarios where linters did not work correclty, and for instance I had to bypassed them.
Below option bypasses the pre-commit and pre-push.
git commit --no-verify
git push --no-verify
See also githooks.
Save uncommitted changes with git stash
Sometimes when we are working we need a way to pause and switch gears to deal with something more critical; often when this happens we aren’t ready to create a git commit; instead, we can use git stash to save our uncommitted changes locally, switch branches and fix the critical issue, switch back to our incomplete feature, and finally run git stash apply to get our unfinished changes back into our branch without affecting the rest of the codebase. Below it shows a real world example of doing this with a critical bug.
1 | # Create a new feature branch. |
Navigate git command pager output with Unix less command
When using a git command that can have a large amount of output (like git log, git diff, or git blame), Git opens the command output in our terminal “pager”; on most modern Unix-based systems, the default pager will be “less“. Learning a few less commands will help us deal with this git command output that opens in the pager. Below it shows some of the most useful of the less commands:
q (quit), j (down), k (up), Ctrl f (forward), Ctrl b (backward), /{search} (search), and n/N (next/previous search result).
It covers some of the most critical less commands; there are more commands available. A good chunk of the commands (and “motions”) of the Unix pagers are also used by vi (or vim) and other Unix programs.
View commit history with git log
It’s often helpful to view the history of a code project; with Git, we can use the git log command to view all commits in our repo. This lets us view information about each commit like the commit id (for use in other git commands), author, author’s email, and commit message. We can format the git log commit output to display more or less information or filter to specific commits using git log {arguments}.
1 | git log {arguments} |
Format commit history with git log arguments
When running the git log command, we can pass in options as arguments to format the data shown for each commit.
Below it shows how to use the oneline, decorate, graph, stat, and p options with git log.
1 | git log --oneline # Condensed info. |
Filter commit history with git log arguments
It will walk through using a bunch of options to filter our git log commits to a more meaningful set (-n, --after, --before, --author, --grep, -S, -G, --no-merges, {ref}..{ref}, {files}). We will also show how all of the formatting and filtering options can be composed together to query exactly what you are looking for in your commit history.
Git log examples
1 | git log -3 # 3 most recent commits. |
Compare file changes with git diff
It can be helpful to see the changes between two sets of code; git diff lets us do this by comparing two Git references and outputting the differences between them. Below it shows how to use git diff along with the --stat, --cached, HEAD, origin/master, file(s)/dir(s) options.
git diff: Show changes between two references; by default it uses the last commit, and the current working directory.
Practical examples for git diff
1 | git diff # Check what exa has changed. |
Show who changed a line last with git blame
When working on a file, we often want to know who made certain changes last; we can use git blame to see details about the last modification of each line in a file. Below it shows and example of using git blame to see who made the last change on a line in a file, and then we use the output of git blame to use in other tools like git log to see the full context of why the change was made and what other parts of the code base were effected at the same time as the line from git blame.
Practical example for git blame
1 | git blame README.js |
Use semantic versioning with git tag
Using git tag we can create references to commits that are immutable; this is usually used for making public releases. Below show how to use git tag and go over common Semantic Versioning (AKA semver) conventions.
Create references to a commit that can be changed.
Practical examples with git tag
1 | git tag v1.0.0 # Create tag with the label v1.0.0. |
1 - Major release, breaking code changes. 0 - Minor release, no breaking code changes, new functionality and maybe some bug fixes. 0 - Patch release, small bug fixes.
Clean up commits with git rebase
Sometimes its nice to clean up commits before merging them into your main code repo; below it goes over using git rebase to squash commits together and then rename the condensed commit message.
Practical examples using git rebase
1 | git status |
git rebase It is DESTRUCTIVE, change the git history, we shouldn’t use rebase in code already pushed in the master branch.
Diagnose which commit broke something with git bisect
Sometimes you find a bug in your project that has been around for a while without being noticed; it can be hard to track down where that bug was introduced and why just by searching through logs and diffs. Git has a slick tool called git bisect that can be used to find out which commit introduced problem in our code - it creates a binary search where the programmer can mark each search commit as good or bad; by the end of the bisect, Git shows you exactly which commit introduced the issue. Below it walks through an example of using git bisect from start to finish.
Practical examples using git bisect
1 | (git-documentation) git bisect start |
Run scripts on git events with git hooks
Git lets us run scripts on git events like pre-commit, pre-rebase, post-commit, post-merge, post-checkout, etc. You can do this by adding an executable file to the ./git/hooks directory which has a name matching the git hook name. Below it walks through this process by setting up a pre-commit hook which runs our npm test and npm run lint npm scripts to ensure we don’t have any failing tests or lint errors before committing
Practical examples using hooks
1 | cd .git |
Configure global settings with git config
You can set up global “git config“ (~/.gitconfig) settings that apply to all git projects on your system. We then add our own git config settings: username, email, editor, and git aliases.
Practical examples using git config
1 | # Create alias |
Remove unnecessary git tracking with .gitignore file
Most projects have automatically generated files or folders from the operating system, applications, package managers etc. Usually, we don’t want to include these types of things in our remote repos because they can clutter the git history/storage and are not applicable to everyone that works on the project. Below it shows how to create a .gitignore file to ignore files and folders from being tracked by git.
Practical examples using .gitignore
1 | touch .gitignore |
Remove all unnecessary git tracking with a global .gitignore file
If you regularly use code editors, GUI tools or other programs that automatically create files and folders, you may want to set up a global .gitignore file which will apply to every repo on your machine. Below it shows how to do that by creating a .gitignore_global file with the dotfiles in our ~/ root directory, and then link it to all git repos using our global .gitconfig.
1 | touch ~/.gitignore_global # Any but recommend by git. |