git push origin feature refspec error

If you try to

git push -u origin feature/branch_name

and you get this error “error: src refspec feature/branch_name does not match any”, it means that your local branch are not named correctly. It should be named

feature/branch_name

as well, not just branch_name. Do a “git branch” to confirm yourself.

Cleaning up git history with git rebase

Git rebase is good when you want to combine some historical commits into one commit. This might be a good idea because your history contains too many unncessary test commits, or if you want to cut down the size of your git objects. On the other hand, changing history can be a dangerous thing, it means that everyone else using your repo needs to acknowledge the change by force pulling.

for example,

git log --oneline
291423b update setup
7732e24 update deployment files
5e0c60f Merge branch 'develop'
e656609 update paths
1f35b9a Merge branch 'develop'
c914ca6 update prod
746eff5 update readme
8754887 update readme
ce9563d update staging

Now we want to remove everything between 291423b and ce9563d. Basically, you want to crunch everything from 291423b down to a point in history, ie ce9563d. Here comes rebase.

git rebase -i ce9563d
pick 8c79382 update
pick 8754887 update readme
pick 746eff5 update readme
pick c914ca6 update prod
pick e656609 update paths
pick 7732e24 update deployment files
pick 291423b update setup

# Rebase ce9563d..cd268a9 onto ce9563d
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

Note that now the latest commit is at the bottom, exactly reverse of what you see in git log. If you delete any of the lines, the commit will be gone. This is a bad bad idea and its best not to do that, instead, use “f” or ‘s’ and leave the first commit as it is like so:

pick 8c79382 update
f 8754887 update readme
f 746eff5 update readme
f c914ca6 update prod
f e656609 update paths
f 7732e24 update deployment files
f 291423b update setup

# Rebase ce9563d..cd268a9 onto ce9563d
#
# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#

rebase will tell you if it encounters any problems. Fix them and you have to force push

git push origin --force

Deploying to wordpress from git

If you are using git and are writing plugins for wordpress, its a hassle to switch between the 2 SCM. Why not commit once and deploy to 2 places? that is what many people are trying to do.

this script does exactly that: https://github.com/benbalter/Github-to-WordPress-Plugin-Directory-Deployment-Script

Create a plugin first. I suggest using all lowercase, eg blarblar-blarblar-blarblar. create a repo for it in github. git clone that plugin in your plugins folder. Make all changes.

Create the version number in the readme and plugin master file.

copy the deploy.sh into the wp-content/plugins folder, one level above your plugin. then run:

 ./deploy.sh

you will be prompted to enter the name of the plugin and everything should work.

bitbucket post hook sample json

Like github, bitbucket sends a useful json post data to a url specified by you if you add a post hook in a the bitbucket repo. The post json can be useful if you want to determine the file changes of the branch that has the change. example json is

Array
(
[payload] => {"repository": {"website": "", "fork": false, "name": "repo_name", "scm": "git", "owner": "your_group", "absolute_url": "/your_group/your_repo/", "slug": "your_repo", "is_private": true}, "truncated": false, "commits": [{"node": "727a3b3c6b37", "files": [{"type": "modified", "file": "code/yourfile.php"}, {"type": "modified", "file": "code/yourfile.php"}], "raw_author": "your name <bernard@youremail>", "utctimestamp": "2014-11-26 04:13:10+00:00", "author": "yourname", "timestamp": "2014-11-26 05:13:10", "raw_node": "727a3b3c6b37f0b9c03fde57943f3f463a12f9e5", "parents": ["2405db2a7a94"], "branch": "develop", "message": "update deploy scripts\n", "revision": null, "size": -1}], "canon_url": "https://bitbucket.org", "user": "yourname"}
)

git pull – force overwrite your code with remote or local changes

Conflicts can be troublesome when you do a git pull or git merge. What if you are pretty sure that you want to use the remote version or your version of the code during a pull/merge conflict? no “git pull -f” doesn’t do it.

To do it really quickly, you can

git fetch
git reset --hard origin/master

To have closer control and do it file by file.

git pull
# assuming conflicts occur with style.css at this moment.
# this forces me to use the remote file. use --ours to use my version.
git checkout --theirs style.css
git add style.css
git commit

insufficient permission for adding an object to repository database .git/objects

If you do a “git add” or other commands and get this error “insufficient permission for adding an object to repository database .git/objects”, it means that you must have used other user to commit or make changes to the git repo before. The best fix is to manually change the user permission of the git objects in your repo, ie

cd your_git_repo/.git/objects
chown your_username:your_username -R *

updating software using git

If your software is version controlled using git for example, you need to version control the software update as well. For file changes, there are 3 possibilities:

a) file modified
b) file deleted
c) new file added

to handle part a) and b), we can run this code in command line

git status | grep modified: | awk '{print $3}' | xargs git add
git status | grep deleted: | awk '{print $3}' | xargs git rm

by this time, “git status” show see only the “untracked files”. manually “git add” the new files.

Note that this is only for file updates. for db updates, things can become extra complicated depending on the infrastructure.

My Favourite Git Commands

I use git everyday and these are the commands that I cannot live without.

HouseKeeping

git status: This command must be used trillion times. Use it anytime to see where you are at.
git log: gives you a quick overview of previous commit
git log -p: gives you an overview of prevous commits + details of files changed.
git log --stats: list of files commited.
git log -p [hash]..[hash] [filename]: changes to a file between different commits, ie hashes.
git diff [hash]..[hash] [file]: see the difference in files between version.
git reset --hard [hash]: reset git to certain previous state, discarding all changes. leave hash out to reset to current HEAD.
git reset dir/files: unstage files.
git clean -df: remove all untracked files from working tree.
git commit --amend: edit the last commit comments.
git add [files]: stage the files to be committed.
git commit: commit the files.
git init --bare: create a new repository for files to be committed to it.
gitk: simple git gui to track commit changes. My favourite GUI.
git stash: save repo in a temp state. "git stash list" to check all the saved state you have.

Branching and Tagging

git checkout -b [new_branch_name] [origin_branch]: create a new branch from current branch and switch into it. if original branch is hosted remotely, can use origin/branch_name instead.
git checkout [filename/branch]: checkout the HEAD version of the file or switch branch.
git tag [your_own_version_number]: create a tag/snapshot of the current status. able to deploy based on the tag.
git describe: good when using tags. let you know where you are.
git branch -a: shows you all the branches and which branch you are in.
git checkout [hash] [file]: checkout an older version of the file.
git remote add origin git@blarblar.com:something/foo.git: add an origin

Forking
supposed you forked someone’s repo in github.

git remote add upstream git@github.com:username/repo.git : add a remote host(upstream) to follow. After this command, do a "git fetch upstream" to get all the remote branches.
git remote -v: gives you an overview of the remote hosts.
git merge upstream/master : merge upstream host with your master.

Pulling and Pushing

It is a good habit to always pull before working on the files, ie committing and pushing. It reduces the chances of conflicts later. Always use git status to track which branch you are in.

git pull [remote] [branch]: pull from remote master and merge to current branch. Make sure you are in local master branch as well. A short cut for this would be just "git pull".
git pull --rebase: pull changes but put your commits above the pulled commits. Good habit to prevent a merge commit upon pulling, again helping to maintain a clean git history.
git push [remote] [branch]: push your changes upstream to remote branch. A short cut for this would be "git push".
git merge [source_branch] [target_branch]: merge all changes from one branch to the another. Able to use the "no-ff" option to create a new commit upon merging. the no-ff option will also keep the branch history.
git merge --squash [source_branch] [target_branch]: good if you want to move all changes in the source branch to target branch as one commit.
git rebase [branch]: useful command to use in feature branch. when master branch is updated, we run this command in your feature branch, ie "git rebase master" to put your commits above the master commits - gives a clean history.
git cherry-pick [hash]: Pick and apply commit from a previous commit on any branch.
git rebase [hash]: compress commits in history. this is a dangerous move if you have multiple people working on the remote repo.
git rebase -i [hash]~[x]: allows you to squash or change commit text on historical commits, starting from [hash] or HEAD and move x commits before, eg HEAD~4.

Git Submodule By Example

If you have been working with version control system for a while, you would know or speculated about the possibility of including references from other projects into your project. From a programmer’s point of view, this feature is useful especially when you need to include code libraries owned by someone else or common header/footer files to be used across different repositories.

Like Subversion externals, git submodule allows one to work with multiple repositories within one main repository. Unfortunately, git submodule resources were scarce on the web. It could also be confusing for people coming from subversion background because it operates differently from it. Despite sharing the same concept, the general feedback was that many people find it hard to digest at a first glance.

In this tutorial, we will be going through an example of how to use git submodule in a typical software development process. We will also be setting up bare repositories from the start, so feel free to skip the first 3 steps if you already know the basics. A bit of basic Git and command line knowledge is assumed.

Say we have 2 developers working on an app that uses a common library (submodule) and this is the workflow:

  • Scenario 1: dev1 is the lead developer and sets up bare origin repository structure under the /mnt/demo directory.
  • Scenario 2: submodule-origin needs something before the team continue. Dev1 creates a master branch and commits a file to the empty submodule-origin.
  • Scenario 3: app-origin cannot be empty as well. Again, dev1 creates a master branch on app-origin and adds a file to it.
  • Scenario 4: The team now has the essential environment to start playing with git submodule. dev1 adds the submodule to its local repo, commits the file and pushes it to submodule-origin.
  • Scenario 5: dev1 is pretty happy with everything and decides to tag his changes.
  • Scenario 6: dev2 comes along and wants to make some code changes to both the app and the submodule. He does a clone, modify some files and commits.
  • Scenario 7: Dev2 is happy with his changes and decides to tag it with v1.0.1
  • Scenario 8: Dev1 now wants to get dev2 changes and does a pull.
  • Scenario 9: Dev1 is not very happy with dev2 changes and decides to revert everything back to v1.0.0

Hopefully, the snapshots of the command line and comments are self-explainatory…

Scenario 1: dev1 is the lead developer and sets up bare origin repository structure under the /mnt/demo directory.


# init user globals first
dev1@localhost:~$ git config --global user.name "dev1"
dev1@localhost:~$ git config --global user.email dev1.localhost

# initialise bare app and submodule repo
dev1@localhost:~$ cd /mnt
dev1@localhost:/mnt$ sudo mkdir {demo,demo/app-origin,demo/submodule-origin}
dev1@localhost:/mnt$ sudo chmod 777 -R demo
dev1@localhost:~/mnt$ cd demo
dev1@localhost:/mnt/demo$ git init --bare app-origin/
dev1@localhost:/mnt/demo$ git init --bare submodule-origin/

Scenario 2: submodule-origin needs something before the team continue. Dev1 creates a master branch and commits a file to the empty submodule-origin.


dev1@localhost:~$ mkdir submodule
dev1@localhost:~$ cd submodule
dev1@localhost:~/submodule$ git init
Initialized empty Git repository in /home/dev1/submodule/.git/
dev1@localhost:~/submodule$ echo submodule > submodule
dev1@localhost:~/submodule$ git add submodule
dev1@localhost:~/submodule$ git commit -m"init"
[master (root-commit) c61fab7] init
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 submodule
dev1@localhost:~/submodule$ git remote add origin /mnt/demo/submodule-origin/
dev1@localhost:~/submodule$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 207 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /mnt/demo/submodule-origin/
 * [new branch]      master -> master

Scenario 3: app-origin cannot be empty as well. Again, dev1 creates a master branch on app-origin and adds a file to it.


# initialse the dev1 directory
dev1@localhost:~$ mkdir app
dev1@localhost:~$ cd app
dev1@localhost:~/app$ git init
Initialized empty Git repository in /home/dev1/app/.git/
dev1@localhost:~/app$ echo dev1 > dev1
dev1@localhost:~/app$ git add app
dev1@localhost:~/app$ git commit -m "init"
[master (root-commit) 28eda11] init
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 dev1
dev1@localhost:~/app$ git remote add origin /mnt/demo/app-origin/ 
dev1@localhost:~/app$ git push origin master
Counting objects: 3, done.
Writing objects: 100% (3/3), 199 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /mnt/demo/app-origin/
 * [new branch]      master -> master

Scenario 4: The team now has the essential environment to start playing with git submodule. dev1 adds the submodule to its local repo, commits the file and pushes it to submodule-origin.


# add a submodule
dev1@localhost:~/app$ git submodule add /mnt/demo/submodule-origin/ submodule

if you are doing it correctly, you should see a .gitmodules file being created.


dev1@localhost:~/dev1$ cat .gitmodules
[submodule "submodule"]
	path = submodule
	url = /mnt/demo/submodule-origin

dev1@localhost:~/app$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#	new file:   .gitmodules
#	new file:   submodule

Let’s add the new files and push


dev1@localhost:~/app$ git add *
dev1@localhost:~/app$ git commit -m "add submodule"
[master c78abf9] add submodule
 2 files changed, 4 insertions(+), 0 deletions(-)
 create mode 100644 .gitmodules
 create mode 160000 submodule
dev1@localhost:~/app$ git push origin master
Counting objects: 4, done.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 350 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /mnt/demo/app-origin/
   a94d038..c78abf9  master -> master

Scenario 5: dev1 is pretty happy with everything and decides to tag his changes.


dev1@localhost:~/app$ git tag v1.0.0
dev1@localhost:~/app$ git push --tags
Total 0 (delta 0), reused 0 (delta 0)
To /mnt/demo/app-origin/
 * [new tag]         v1.0.0 -> v1.0.0

Scenario 6: dev2 comes along and wants to make some code changes to both the app and the submodule. He does a clone, modify some files and commits.


# init user
dev2@localhost:~$ git config --global user.name dev2
dev2@localhost:~$ git config --global user.email dev2@localhost.com

# clone the app-origin first.
dev2@localhost:~$ git clone /mnt/demo/app-origin/ app
Initialized empty Git repository in /home/dev2/app/.git/
dev2@localhost:~/app$ ls
dev1  submodule

dev2 modifies the dev1 file and add it to be committed later.


dev2@localhost:~/app$ echo "dev1 dev2" > dev1
dev2@localhost:~/app$ git add dev1

let’s see what’s in the submodule


dev2@localhost:~/app$ ls submodule

Nothing?? Remember that git submodules are to be treated differently? Cloning the app doesn’t clone the submodule. Dev2 will have to do that manually.


dev2@localhost:~/app$ git submodule init
Submodule 'submodule' (/mnt/demo/submodule-origin) registered for path 'submodule'
dev2@localhost:~/app$ git submodule update
Initialized empty Git repository in /home/dev2/app/submodule/.git/
Submodule path 'submodule': checked out 'c61fab7265554f3e99632376102831e6712622b5'

now, we should see something in the submodule dir.


dev2@localhost:~/app$ ls submodule/
submodule

the “git submodule update” also created a dummy branch for you


dev2@localhost:~/app$ cd submodule/
dev2@localhost:~/app/submodule$ git branch
* (no branch)
  master

Now say dev2 wants to fix a bug in the submodule and he wants everyone using the submodule to get it. To push changes in the submodule, he needs to re-checkout the master branch and push. Note that he needs to push again in the submodule dir because the submodule is now a repo within another repo. Despite the hierarchy, both repo need to be managed as if they are separate.

dev2 now checkout the master branch, modify the submodule file and commits.


dev2@localhost:~/app/submodule$ git checkout master
dev2@localhost:~/app/submodule$ echo "fixed bug" >> submodule 
dev2@localhost:~/app/submodule$ git add submodule
dev2@localhost:~/app/submodule$ git commit -m "fixed bug"
[master 9ddfa96] fixed bug
 1 files changed, 1 insertions(+), 0 deletions(-)
dev2@localhost:~/app/submodule$ git push origin master
Counting objects: 5, done.
Writing objects: 100% (3/3), 260 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /mnt/demo/submodule-origin
   c61fab7..9ddfa96  master -> master

back to the root, we should see the files/dir modified.


dev2@localhost:~/app/submodule$ cd ..
dev2@localhost:~/app$ git status
# On branch master
# Changed but not updated:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   dev1
#	modified:   submodule
#

dev1 need to do another commit and push in the top level to include the submodule changes.


dev2@localhost:~/app$ git add dev1 submodule
dev2@localhost:~/app$ git commit -m "dev2 made both app and submodule changes"
[master a542a08] dev2 made both app and submodule changes
 2 files changed, 2 insertions(+), 2 deletions(-)
dev2@localhost:~/app$ git push origin master
Counting objects: 5, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 327 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /mnt/demo/app-origin/
   c78abf9..a542a08  master -> master

Scenario 7: ev2 is happy with his changes and decides to tag it with v1.0.1dev2 comes along and wants to make some code changes to both the app and the submodule, so he does a clone, modify the files and commit.


dev2@localhost:~/app$ git fetch --tags
From /mnt/demo/app-origin
 * [new tag]         v1.0.0     -> v1.0.0
dev2@localhost:~/app$ git tag v1.0.1
dev2@localhost:~/app$ git push --tags
Total 0 (delta 0), reused 0 (delta 0)
To /mnt/demo/app-origin/
 * [new tag]         v1.0.1 -> v1.0.1

Scenario 8: Dev1 now wants to get dev2 changes and does a pull.


dev1@localhost:~/app$ git pull origin master
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /mnt/demo/app-origin
 * branch            master     -> FETCH_HEAD
Updating c78abf9..a542a08
Fast-forward
 dev1      |    2 +-
 submodule |    2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

Let’s check on the submodule file…


dev1@localhost:~/app$ cat submodule/submodule 
submodule

Opps, where was the change that dev2 made on the submodule/submodule file? Dev1 tries doing a “git submodule update” and got the changes.


dev1@localhost:~/app$ git submodule update
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /mnt/demo/submodule-origin
   c61fab7..9ddfa96  master     -> origin/master
Submodule path 'submodule': checked out '9ddfa961f29c3866cdcbef697811a185af3fc407'

Scenario 9: Dev1 is not very happy with dev2 changes and decides to revert everything back to v1.0.0


dev1@localhost:~/app$ git checkout v1.0.0
M	submodule
Note: checking out 'v1.0.0'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at c78abf9... add submodule

dev1@localhost:~/app$ cat dev1
dev1
fixed bug

dev1 file is now reverted. How about the submodule?


dev1@localhost:~/app$ cat submodule/submodule 
submodule

Opps, submodule file has not been reverted. dev1 does another submodule update to grab the old changes for the submodule.


dev1@localhost:~/app$ git submodule update
Submodule path 'submodule': checked out 'c61fab7265554f3e99632376102831e6712622b5'
dev1@localhost:~/app$ cat submodule/submodule 
submodule

Hopefully, this example covers the basic use of git submodule. The trick is to treat the submodule as a separate repo within the top working repo. Remember to do “git submodule update” after you do a pull (if you wish to update the submodule).

Another thing to note is that if you create a branch from a branch containing a submodule, the submodule will remain in the same state irregardless of which module branch you are in. This is important to know if you have separate branches within the submodule itself.

using git ignore

gitignore is helpful when you want to ignore certain files (such as the config files) while working on the files checked out from a git repository. You do not want to commit the config files because other people working on the same repository would also pull your config files which is bad.

Why ignore? because it will be easier for you to go through the files that have been changed before committing. Usually, we do a “git status” before committing. By not ignoring the config files, they will show up in the status which can be annoying.

How do we implement git ignore?

just create a .gitignore file in any directory containing the files or directory that you want to ignore. for example we want to ignore wp-config.php and .htaccess in the root directory, add these 2 lines:

/wp-config.php
/.htaccess

note: the slashes infront is important because we do not want to ignore files with similar names in the subdirectory. To ignore .htaccess in the css directory for example, we can either place /css/.htaccess under the root directory or create a new .gitignore file under the css directory and just put a /.htaccess in there.

if for some reason, gitignore doesnt ignore .htaccess for example (I did encounter this bug before), do

git update-index --assume-unchanged .htaccess