Skip to content

Instantly share code, notes, and snippets.

@CTimmerman
Last active April 22, 2024 02:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CTimmerman/907bff561864be3d79ff0b2a05ddcd15 to your computer and use it in GitHub Desktop.
Save CTimmerman/907bff561864be3d79ff0b2a05ddcd15 to your computer and use it in GitHub Desktop.
Simple git workflow
  1. Install Git distributed version control software.
  2. Set up your default credentials (or display without a value to set):
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

or if he's a GitHub user, so you see his icon: johndoe@users.noreply.github.com

For example on MacOS:

~/Documents/code/test❯ git config --list
credential.helper=osxkeychain
init.defaultbranch=main
user.name=Cees Timmerman
user.email=c.timmerman@company
filter.lfs.clean=git-lfs clean -- %f
filter.lfs.smudge=git-lfs smudge -- %f
filter.lfs.process=git-lfs filter-process
filter.lfs.required=true
core.excludesfile=/Users/ct/.gitignore_global
core.autocrlf=input
difftool.sourcetree.cmd=opendiff "$LOCAL" "$REMOTE"
difftool.sourcetree.path=
mergetool.sourcetree.cmd=/Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh "$LOCAL" "$REMOTE" -ancestor "$BASE" -merge "$MERGED"
mergetool.sourcetree.trustexitcode=true
commit.template=/Users/ct/.stCommitMsg
core.sshcommand=ssh -i ~/.ssh/myed25519key
~/Documents/code/test❯ cat ~/.gitconfig
[user]
	name = Cees Timmerman
	email = c.timmerman@company
[filter "lfs"]
	clean = git-lfs clean -- %f
	smudge = git-lfs smudge -- %f
	process = git-lfs filter-process
	required = true
[core]
	excludesfile = /Users/ct/.gitignore_global
	autocrlf = input
[difftool "sourcetree"]
	cmd = opendiff \"$LOCAL\" \"$REMOTE\"
	path =
[mergetool "sourcetree"]
	cmd = /Applications/Sourcetree.app/Contents/Resources/opendiff-w.sh \"$LOCAL\" \"$REMOTE\" -ancestor \"$BASE\" -merge \"$MERGED\"
	trustExitCode = true
[commit]
	template = /Users/ct/.stCommitMsg
[core]
	sshCommand = "ssh -i ~/.ssh/myed25519key"

Generate a key with ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/myed25519key -C "For Git from MacOS." and add the ~/.ssh/myed25519key.pub content to your Bitbucket server keys for example.

Main or master is the (preferably working) development branch in most git branching models. (GitHub Flow, GitLab Flow, etc.; not Git Flow.) If you want to stabilize for a release, create a release branch and only merge bug fixes from master to it by cherry picking. When a branch works in your local environment (e.g. VirtualBox), rebase and push it to the remote. Ideally, merge requests should get reviewed and the remote production branch should get tested and deployed after it passes.

Check out new remote branch:

$ git fetch
$ git checkout -t origin/TICKET2  # Or `git switch TICKET2` since 2020.
Branch 'TICKET2' set up to track remote branch 'TICKET2' from 'origin'.
Switched to a new branch 'TICKET2'

And delete the old branch locally:

git branch -d TICKET1

Or if that complains:

git branch --delete --force TICKET1

Or create a new local branch and push it to remote:

$ git checkout -b TICKET2
Switched to a new branch 'TICKET2'
$ git add .  # Stage all changes.
$ git reset DEBUG_FILE  # Unstage this file.
$ git status  # Verify changes.
$ git commit -m "MESSAGE"
$ git push -u origin TICKET2  # Note the lack of a slash.

Publish and track a new branch without getting a src refspec error:

git push -u origin HEAD:NEW_BRANCH_NAME

That -u sets to track the new upstream branch just like this:

git branch -u origin/NEW_BRANCH_NAME

List all branches:

git branch -a

Rename local branch:

git branch -m NEW_BRANCH_NAME

Delete remote branch:

git push origin -d REMOTE_BRANCH_NAME

Remove remotely deleted branches from local remotes:

git fetch --prune

If you used https and are tired of entering your password, switch to git with a private key (after adding ssh-add ~/.ssh/id_ed25519 to your shell init):

git remote remove origin
git remote add origin git@gitlab.company.com:project/components/subproject.git
git branch -u origin/TICKET TICKET

Alternatively on GitHub you can use a more fine-grained personal access token: git remote set-url origin https://<token>@github.com/<user>/<repo>.git

Get origin with git remote -v. You could also add one for no apparent reason.

Merge the main branch before pushing to it:

git merge origin/master

Or if you want to rewrite history which nobody else depends on, rebase:

git rebase origin/master
git push --force-with-lease

Conflicting files should be edited and staged as usual before committing the merge.

If git pull (with git config pull.rebase true to avoid littering your local branch with merge commits) complains, autostash:

$ git pull
error: cannot pull with rebase: You have unstaged changes.
error: please commit or stash them.

$ git pull --rebase --autostash
Updating 48a1590..660f95a
Created autostash: ac9d78e
Fast-forward
 ide.html | 11 +++++++++++
 1 file changed, 11 insertions(+)
 create mode 100644 ide.html
Applied autostash.

Auto-autostash with git config rebase.autoStash true

If you messed up and nobody is basing work on that yet, this fixes it:

git reset --hard LAST_GOOD_HASH
git push --force-with-lease

If your repo is FUBAR, rename it and clone again. You can compare file versions using commit hashes from git log --graph: git diff OLD_HASH NEW_HASH [FILE]

To gatekeep commits, use .git\hooks\pre-commit with your favorite linter, e.g.

#!/bin/sh
pylint

or similar but more bloated versions generated by a Git hooks package manager such as the confusingly-named pre-commit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment