Git can be challenging to learn and often makes the easy complicated in its attempt to make the complicated easy. This is a collection of notes, aliases, shortcuts and explanations that help me to survive.
# Show uncommitted changes:
# Usage: git-changes
alias git-changes='git commit -a --verbose --dry-run'
# Show last commit with filenames and type of change
alias git-last='git log -1 --name-status'
# Revert uncommitted changes in a file:
# Usage: git-revert <file.ext>
alias git-revert='git checkout'
# Revert ALL local changes to master. Can use git stash to save a copy.
# Usage: git-revert-everything
alias git-revert-everything='git fetch origin && git checkout master && git reset --hard origin/master'
# Totally reset local to what is on github with a final cleaning
# Usage: git-reset-to-github
alias git-reset-to-github='git fetch origin && git reset --hard origin/master && git clean -ffdx'
# Squash multiple commits into one for readability
# Usage: git-squash
alias git-squash='git rebase --interactive'
# Push up from a new (current) branch without having to remember:
# git push --set-upstream origin <branchname>
# Usage: git-push-branch
alias git-push-branch="git push --set-upstream origin $(git branch | awk '/^\* / { print $2 }') > /dev/null"
# Grab latest changes from the original project you forked on GitHub.
# Before doing this, you should have configured:
# git remote add upstream https://github.com/ORIGINAL/ORIGINAL.git
# If you have a branch, you should go there and type `git merge master`.
# Usage: git-merge-from-upstream
alias git-merge-from-upstream='git fetch upstream && git checkout master && git merge upstream/master'
# Call git-fixup (from bash) to add your current changes to the last commit and force push.
function git-fixup () {
local PREV_COMMIT=$(git log -1 | perl -n -e "/^commit (.+)/ && print \"\$1\n\"")
echo "Last commit:"
git log -1
echo -e "Fixing up last commit: $PREV_COMMIT"
# Commit the change without signing because the rebase later is signed.
git commit -a --no-gpg-sign --fixup "$PREV_COMMIT" &&
# Non-interactive rebase using `true` as EDITOR
# http://stackoverflow.com/a/12395024/1117929
GIT_SEQUENCE_EDITOR=true git rebase --interactive HEAD~2 &&
git push --quiet --force
}
# Opposite of `git add`, not to be confused with `git rm`
git config --global alias.unadd 'reset HEAD --'
git config --global alias.unstage 'reset HEAD --'
# Config git rebase -i to always autosquash.
# If you use `git commit --fixup [hash]`, then `git rebase -i HEAD~2` you will see that it marks the fixup items.
# So you just need to hit save from the editor.
# BTW: Why do I still need to go though this stupid interactive session when using "autosquash"!?
# Seems the hack-job workaround is to set `GIT_SEQUENCE_EDITOR=true`... see `git-fixup` above.
git config --global rebase.autosquash true
# When pushing, always use the current branch. Duh!
git config --global push.default current
git config --global user.email [EMAIL ADDRESS OF YOUR PGP IDENTITY]
git config --global user.signingkey [YOUR KEY HERE]
git config --global commit.gpgsign true # Only works in git >= 2
You should also add your OpenPGP public key to GitHub so that verification info is displayed to users.
NOTE: Both git
and GitHub will show that code was signed with your signing subkey (rather than primary key). This may be confusing for users because normally the primary key is used / publicly shared by devs and subkeys are selected quietly in the background as needed. See example here and click on the green "Verified" button.
Show commit signature info (more info)
git log --show-signature -1 # Details of last commit sig.
git log --pretty="format:%h %G? %aN %s" # Log of last commits. The "G" means good signature, "N" means no sig.
- http://ohshitgit.com - Solutions to common problems in plain English.
git add --update # stages only the files which are already tracked and not new
git commit --amend # Change previous commit message and / or add staged files.
git show --name-status # Show diff of previous commit
git log --stat # Show latest changes committed
git checkout [BRANCH NAME] # To switch to a particular branch
git checkout -b [BRANCH NAME] # To CREATE a new branch
git remote set-url origin [email protected]:jonathancross/pics.jonathancross.com.git # Allow git push via ssh without password
git remote -v # Show the remotes that are configured: https://help.github.com/articles/fork-a-repo/
git branch newbranch # Creates a new branch using your current state in master
git reset --hard HEAD~1 # Go back 1 commit. You *will* lose uncommitted work.
git checkout newbranch # Switch to the new branch you made from master.
# Assuming remote is jonathancross/Signal-Android.git and changes are on branch patch-1
git clone [email protected]:jonathancross/Signal-Android.git
cd Signal-Android
git checkout patch-1 # NOT `git branch patch-1` which will CREATE patch-1!!!!!!!!!
git branch # Check that you are now on patch-1
git log --stat -1 # Look for your commit
git commit --amend
git push -f
git rebase -i HEAD~3
Then edit message like so:
pick 3074590 The message we want to keep.
fixup 917fdb0 Comment to discard 1
fixup b04757a Comment to discard 2
Normally, you can then simply force push the single "fixed" commit, replacing the two you had:
git push -f # Force push the amended commit containing all 3 changes under one commit.
You might have to do some of this:
git add <file> # Not clear why an existing file needs to be "added", but this is the way to mark resolution of conflicts.
git rebase --continue # Continue a partial rebase if needed
git commit --amend # Fix the commit message
git push -f # Force push the amended commit & message
If you want to set your new branch to start at some time in the past, just add that commit hash to the end of your git branch
git log # Get the commit hash of your starting point
git branch new-branch e673afd45c5246ac0f16f30472c677bcb9c0fd7b
git checkout new-branch
- To merge a branch back into master, use a pull request. Will go from right (compare or "head" branch, what you did) to left ("base" where it should go)!
- To merge changes made in original to the fork, click on the green arrows, change the base, then create pull request, then merge the pull request.
Eg: Pull this locally to test: monero-project/monero-gui#786 (branch name is android_dockerfile
)
cd monero-project
git fetch upstream pull/786/head:android_dockerfile
Can probably then push to my fork, then submit a PR to them. Need to test.
In many situations, I'd like to be able to submit a series of unrelated pull requests to a repo.
Unfortunately, if the first PR was from master
branch (the default), future branches you create will include those changes unless you tell the branch to point to an earlier commit.
Bottom line: Always start with a new branch! If you forgot, then see Making a new branch after having already added changes in master above.
WTFPL - See LICENSE for more info.