Thursday, June 12, 2014

Handy Git Aliases


git config --global alias.accept-remote-diffs 'merge origin/master'
git config --global alias.acp '!f() { git add-commit "$1" && git push; }; f'
git config --global alias.acpom '!f() { git add-commit "$1" && git push -u origin master; }; f'
git config --global alias.acpcb '!f() { git add-commit "$1" && git push origin `current-git-branch-name`; }; f'
git config --global alias.add-all '!git add-updated && git add-untracked'
git config --global alias.add-commit '!f() { git add-all && git commit -m "$1"; }; f'
git config --global alias.add-commit-pristine '!f() { git-add-commit-pristine }; f'
git config --global alias.add-untracked '!f() { git-add-untracked }; f'
git config --global alias.add-updated 'add --update :/'
git config --global alias.apply-gitignore-to '!f() { git rm --cached "$@"; }; f'
git config --global alias.clear-alias '!f() { git config --global --unset alias."$@"; }; f'
git config --global alias.clobber-this-branch '!f() { (CURRENT_BRANCH_NAME=`current-git-branch-name`; if [ $CURRENT_BRANCH_NAME = "master" ]; then echo "Cannot run this on master branch" && exit 1; fi; git delete-remote-branch $CURRENT_BRANCH_NAME; git checkout master; git delete-local-branch $CURRENT_BRANCH_NAME;); }; f'
git config --global alias.config-add-remote-origin '!f() { git remote rm origin 2>/dev/null; git remote add origin "$@"; }; f'
git config --global alias.config-make-pulls-merge 'config branch.master.rebase false'
git config --global alias.config-make-pulls-rebase 'config branch.master.rebase true'
git config --global alias.config-onetime-email '!f() { git config --global user.email "$@"; }; f'
git config --global alias.config-onetime-username '!f() { git config --global user.name "$@"; }; f'
git config --global alias.config-only-push-current-branch 'config --global push.default tracking'
git config --global alias.config-project-defaults '!f() { git config-add-remote-origin git@$REMOTE_GIT_ACCOUNT/$1.git; git config-only-push-current-branch; git config-make-pulls-rebase; }; f'
git config --global alias.config-remote-origin-push-head 'config remote.origin.push HEAD'
git config --global alias.create-and-switch-to-branch '!f() { create-git-branch "$@" 2>/dev/null; git config branch."$@".remote origin; git config branch."$@".merge refs/heads/"$@"; }; f'
git config --global alias.create-and-switch-to-new-empty-branch '!f() { git symbolic-ref HEAD refs/heads/$@;rm .git/index;git clean -fdx;echo "\nAdd files, then run: $ git add-commit \"YOUR_MSG\"; git push origin $@\n"; }; f'
git config --global alias.create-branch2 '!f() { create-git-branch2 "$@"; }; f'
git config --global alias.create-local-branch 'checkout -b'
git config --global alias.create-new-repo '!f() { mkdir "$@"; cd "$@"; touch README.md; git init; git add README.md; git commit -m "first commit"; git remote add origin git@"$REMOTE_GIT_ACCOUNT"/"$@".git; }; f'
git config --global alias.delete-alias '!f() { git config --unset alias."$@"; git config --global --unset alias."$@"; }; f'
git config --global alias.delete-local-branch 'branch -d'
git config --global alias.delete-remote-branch 'push origin --delete'
git config --global alias.delete-unstaged '!f() { (echo "";echo "THE FOLLOWING FILES WILL BE DELETED:";git diff --name-only; echo "";echo "ARE YOU SURE? (CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...)";read x;set -x;`git diff --name-only`|xargs rm); }; f'
git config --global alias.delete-untracked '!f() { (echo "";echo "THE FOLLOWING FILES WILL BE DELETED:";git clean -f --dry-run; echo "";echo "ARE YOU SURE? (CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...)";read x; echo "";echo "THE FOLLOWING DIRECTORIES WILL BE REMOVED:";git clean -f -d --dry-run; echo "";echo "ARE YOU SURE? (CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...)";read x;set -x;git clean -f; git clean -f -d); }; f'
git config --global alias.diff-inline 'diff --word-diff'
git config --global alias.diff-remote-master '!f() { git difftool origin/master `current-git-branch-name` -Y; }; f'
git config --global alias.diff-stage-master '!f() { git difftool master `current-git-branch-name` -Y; }; f'
git config --global alias.discard-changes-to-unstaged-file '!f() { git checkout -- "$@"; }; f'
git config --global alias.discard-local-changes '!f() { git reset --hard origin/master && git pull origin master; }; f'
git config --global alias.fetch-and-show-diffs '!git fetch origin && git diff origin/master & echo "Manually merge conflicts. Then, run: $ git accept-remote-diffs"'
git config --global alias.go-to-new-repo '!f() { git link-to-new-repo "$@"; cd "$@"; }; f'
git config --global alias.init-gh-pages '!f() { git symbolic-ref HEAD refs/heads/gh-pages && rm .git/index && git clean -fdx && echo "hello, gh-pages" > index.html; git acpcb "initial gh-page";  }; f'
git config --global alias.link-to-new-repo '!f() { echo "Git repo: $REMOTE_GIT_ACCOUNT/$@.git must already exist."; echo "CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...";read x; mkdir "$@"; cd "$@"; touch README.md; git init; git add README.md; git commit -m "add empty readme file"; git config-project-defaults "$@"; git push -u origin master; echo "You just created a new local repo ($@) that is linked to $REMOTE_GIT_ACCOUNT/$@.git"; }; f'
git config --global alias.list-aliases '!f() { git config --get-regexp alias; }; f'
git config --global alias.list-configs '!f() { git config --list; echo ""; echo "Your git config file: $HOME/.gitconfig"; }; f'
git config --global alias.list-local-branches 'branch'
git config --global alias.list-remote-branches 'branch -r'
git config --global alias.list-unstaged-filenames '!f() { (git diff --name-only); }; f'
git config --global alias.merge-feature-branch-into-master '!f() { (CURRENT_BRANCH_NAME=`current-git-branch-name`; git checkout master; git merge $CURRENT_BRANCH_NAME; git status; echo ""; echo "If no problems, then run: $ git push" ); }; f'
git config --global alias.merge-feature-branch-to-remote-master '!f() { git push origin `current-git-branch-name`:master; }; f'
git config --global alias.merge-feature-branch-to-stage-master '!f() { git checkout -B master `current-git-branch-name`; }; f'
git config --global alias.pretty-log "log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all"
git config --global alias.push-current-branch-to-another '!f() { echo "Assumes you have already added and committed files to 'from-branch' (and your remote is named 'origin')."; echo "CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...";read x; git push origin $1:$2; }; f'
git config --global alias.push-local-branch "push origin `current-git-branch-name`"
git config --global alias.rebase-onto-master 'rebase origin/master'
git config --global alias.rename-local-git-branch '!f() { git branch -m $1 $2; }; f'
git config --global alias.show-commits-that-exist-in-master 'cherry -v master'
git config --global alias.show-local-branches 'branch'
git config --global alias.show-local-log 'log --oneline --decorate'
git config --global alias.show-log-graph 'log --graph --decorate --pretty=oneline --abbrev-commit master origin/master master'
git config --global alias.show-log-with-tags 'log --oneline --decorate'
git config --global alias.show-remote-log "log --graph --decorate --pretty=oneline --abbrev-commit master origin/master `current-git-branch-name`"
git config --global alias.show-sha1-branch '!f() { git branch -a --contains "$@"; }; f'
git config --global alias.show-sha1-tag '!f() { git name-rev --name-only "$@"; }; f'
git config --global alias.switch-to-anothers-branch '!f() { git checkout -t "$@"; }; f'
git config --global alias.switch-to-branch '!f() { git checkout "$@"; }; f'
git config --global alias.switch-to-master-branch 'checkout master'
git config --global alias.undo-all-working-dir-changes-including-new-files '!f() { echo "ARE YOU SURE? (CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...)";read x; git reset --hard; git clean -f -d; git clean -f -x -d; }; f'
git config --global alias.undo-last-git-commit-and-delete-local-changes-too '!f() { git reset --hard HEAD^; git push -f; }; f'
git config --global alias.undo-last-git-commit-but-keep-local-changes 'reset --soft HEAD^'
git config --global alias.untracked 'ls-files --other --exclude-standard'
git config --global alias.update-comment-for-unpushed '!f() { git commit --amend -m "$1"; }; f'
git config --global alias.wipe-local-master-replace-with-remote '!git clean -d -x -f && git fetch --all && git reset --hard origin/master'


Notes

Error on Linux

If you get an error mentioning a problem with ":/" when running git acp, likely when you are on a linux operating system, then replace the following git config:


git config --global alias.add-all '!git add -A'


Simple workflow

Create a local feature branch and switch your local workspace to point to it.


git create-local-branch new_feature


Make changes to your local source code.

Commit your changes to your local repo.


git commit -a


This will open your editor where you can see the files being committed and add your commit comment (to the first line).

Note that if you don't want to add every file you've been working on then add each file individually with git add <FILENAME> and then run git commit to commit add your commit comment.

Push your changes to your remote repo, e.g. github.


git push-local-branch


If you are using remote git repo features, like git workflow, now is the time to go to your remote repo and create a pull request.

Your pull request will hopefully pass peer code review. You may need to read comments from peers and perform fixes that you will subsequently push up to this branch and eventually all will be good and your merge master will merge your branch (and may also delete your remote branch to keep things clean on the server.)

View a list of all branches you're working on


git list-local-branches


Delete remote branch


git delete-remote-branch new_feature


Delete local branch


git delete-local-branch new_feature


link-to-new-repo

After you create a git repository, e.g., on github.com or bitbucket.org, this should probably be the first command you run.


$ git link-to-new-repo golang-samples
Git repo: github.com:l3x/golang-samples.git must already exist.
CTRL+C TO ABORT --OR-- ENTER TO CONTINUE...

Initialized empty Git repository in /Users/lex/dev/go/golang-samples/.git/
[master (root-commit) 6fd5651] first commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 README.md
error: Could not remove config section 'remote.origin'
You just created a new local repo (golang-samples) that is linked to github.com:l3x/golang-samples.git

You can safely ignore the error: Could not remove config section 'remote.origin' message; There were no previous remote origins since this is the first time you initialized your local git repo.

You should make sure that your public key in ~/.ssh is properly configured.

This command assumes you have the environment variable (REMOTE_GIT_ACCOUNT) set to your repo:username.

You can run this command in its own shell and set REMOTE_GIT_ACCOUNT just before running the git command as follows:

(export REMOTE_GIT_ACCOUNT=bitbucket.org:username && git link-to-new-repo reponame)


This command performs the same commands (and a few more goodies) as you might find in the Create a new repository on the command line help section at your remote git repo:

touch README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin https://github.com/l3x/golang-samples.git
git push -u origin master


wipe-local-master-replace-with-remote

wipe-local-master-replace-with-remote has a long alias for a reason. It is destructive and you really need to understand that all local files will be removed (and replaced with the remote files) before running this one.

acp

If you run $ git acp 'my commit message' without first setting the upstream origin, then you'll get an error like this:

 1 file changed, 1 insertion(+)
 create mode 100644 index.html
fatal: The current branch gh-pages has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin gh-pages


Solution: Create/initialize your local repo using the $ git link-to-new-repo <PROJECT_NAME> command and it will set your git origin for you.

fatal: The current branch master has multiple upstream branches

If you run $ git push and get an error like this:

$ git push
fatal: The current branch master has multiple upstream branches, refusing to push.

Solution: Run the following command $ git config-remote-origin-push-head and try again.

Sometimes, when you push to the master branch, without passing any parameters to the git push command, you'll get that error.

switch-to-anothers-branch

When you need to pull another team member's branch into your workspace (to work on it) you need to create a local branch. This alias does that and sets up tracking so that you can run git push after making changes.

show-sha1-tag

The name-rev command uses the tilde "~" character to indicate the position of a commit relative to tags in the project. If "5" comes after the "~" character, then that means that this commit is located 5 commits prior to the tag displayed. If you are working off a master branch it may look like this: "master~5". If you are creating release branches and tagging them as such, it may look like this: "tags/v1.2.0~5".

config-only-push-current-branch

By default, git push will push all local branches that have matching remote branch names. Run this alias once (it sets a global config setting) to prevent this default behavior and cause git to only push the branch you are currently working on.

config-make-pulls-rebase

If you are working solo on the master branch or if you are working on a team that works off the same branch, e.g., "development" (and your team is not using github pull requests) and you don't want your git history polluted with merge bubbles, then run this alias once (it sets a global config setting).

config-make-pulls-merge

If you are merging feature branches into a release branch (or have another scenario where you want to see exactly what happened with the merge), then run this alias once (it sets a global config setting).

config-remote-origin-push-head

If you go off the reservation and find yourself working on the master branch and you attempt to run git push without arguments and get an error like the following...

$ git push
fatal: The current branch master has multiple upstream branches, refusing to push.


... then, you should remove the following two lines from the [branch "master"] section in your ~/.gitconfig file

 remote = origin
 merge = refs/heads/master


and run git config-remote-origin-push-head


Errors

Unable to create git alias

If you get the following error message...

error: could not lock config file .git/config: No such file or directory


...when attempting to create a git alias, then run the following commands:

$ mkdir ~/.git
$ git config-add-global-email-account <YOUR_EMAIL@YOUR_HOST.COM>



Scripts

current-git-branch-name


# Filename: current-git-branch-name
#!/usr/bin/env ruby
# Filename: current-git-branch-name
puts `git branch`.split("\n").select{|i| i.include?('* ')}[0][2..-1]

git-add-untracked


# Filename:  git-add-untracked
(IFS=$'\n'; files=(`git untracked`); for file in "${files[@]}"; do git add $file;  if [ "$?" != "0" ]; then echo "<< run dos2unix  for this file. Then, git add ;git commit --amend --no-edit\n"; fi; done)
if [ "$?" != "0" ]; then
  echo "If you see something like:  fatal: CRLF would be replaced by LF in FILE_NAME."
  echo "Then run:  $ dos2unix on each FILE_NAME  ... and try again."
fi

git-add-commit-pristine


# Filename:  git-add-commit-pristine
MSG=$1
MY_NAME=$(basename $0)
if [ "$MSG" == "" ]; then
    echo "Usage:  $MY_NAME "
    echo ""
    echo "Example:  $MY_NAME 'update readme'"
    exit 1
fi
git add-commit "$MSG" && git fetch && git rebase-from-master && git merge-feature-branch-into-master && git push

create-git-branch2


# Filename: create-git-branch2
# Note:     This also replaces ' ' with '-' and lowercases the branch name
# Note:     This is named "create-git-branch2" b/c git-extras has a script named git-create-branch

BRANCH_NAME=$1
if [ "$BRANCH_NAME" == "" ]; then
    BRANCH_NAME=$(date +%Y%b%d-%H%M)
else
   IFS=' '
   ALL_ARGS="$*"
   echo "ALL_ARGS: $ALL_ARGS"
   BRANCH_NAME=`echo $ALL_ARGS | tr '[:upper:]' '[:lower:]' | tr ' ' '-'`
   echo "BRANCH_NAME: $BRANCH_NAME"
fi

if ( git show-ref --verify --quiet refs/heads/$1 ); then 
    echo "ERROR - Branch ($BRANCH_NAME) already exists." 
    exit 1
else 
    if ( git show-ref --verify --quiet refs/remotes/origin/$BRANCH_NAME); then 
        echo "ERROR - Remote branch ($BRANCH_NAME) already exists." 
        exit 1
    else
        echo "Switching to master..."
        git checkout master 

        echo "Fetching origin..."
        git fetch origin

        echo "Pulling master..."
        git pull

        echo "Creating new branch ($BRANCH_NAME)..."
        git checkout --track -b $BRANCH_NAME 

        echo "Done."
    fi 
fi



Aliases

gcb


alias gcb='git create-and-switch-to-branch


gcb usage


$ gcb feature1
Switching to master...
Your branch is up-to-date with 'origin/master'.
Fetching origin...
Pulling master...
Current branch master is up to date.
Creating new branch (feature1)...
Branch feature1 set up to track local branch master.
Done.


That just created a branch named feature1 and setup the refs so that you can start using git push (without every any having to add -u origin feature1.

git config file after running gcb


feature1 ~/tmp/bogus $ cat .git/config
[core]
 repositoryformatversion = 0
 filemode = true
 bare = false
 logallrefupdates = true
 ignorecase = true
 precomposeunicode = true
[remote "origin"]
 url = git@github.com:l3x/bogus.git
 fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
 remote = origin
 merge = refs/heads/master
[branch "feature1"]
 remote = origin
 merge = refs/heads/feature1





Global Git Config

Perform git clones using https rather than the git protocol.


git config --global url."https://".insteadOf git://



References

http://lexsheehan.blogspot.com/search?q=add-commit
http://stackoverflow.com/questions/1125968/force-git-to-overwrite-local-files-on-pull
http://stackoverflow.com/questions/2514270/how-to-check-for-changes-on-remote-origin-git-repository
http://stackoverflow.com/questions/5772192/git-how-can-i-reconcile-detached-head-with-master-origin
http://mislav.uniqpath.com/2010/07/git-tips/

This work is licensed under the Creative Commons Attribution 3.0 Unported License.

No comments:

Post a Comment