Git allows us to maintain multiple branches of development. This is common and consider a must to develop with git. You may switch between branches to enjoy isolate development workflow.
To ease the explanation, we create a bare repository as origin and 2 cloned repository from origin.
$ mkdir project.git $ cd project.git/ $ git init --bare Initialized empty Git repository in /tmp/test.branch/project.git/ $ cd .. $ git clone project.git clone1 Initialized empty Git repository in /tmp/test.branch/clone1/.git/ warning: You appear to have cloned an empty repository. $ cd clone1 $ echo "This is readm" > readme $ git add readme $ git commit -m "first commit" [master (root-commit) 8b60032] first commit 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 readme $ git push No refs in common and none specified; doing nothing. Perhaps you should specify a branch such as 'master'. fatal: The remote end hung up unexpectedly error: failed to push some refs to '/tmp/test.branch/project.git' $ git push origin master Counting objects: 3, done. Writing objects: 100% (3/3), 215 bytes, done. Total 3 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (3/3), done. To /tmp/test.branch/project.git * [new branch] master –> master $ cd .. $ git clone project.git clone2 Initialized empty Git repository in /tmp/test.branch/clone2/.git/ $ ls -a clone2 . .. .git readme
Create git branch
Let’s create a new branch “newfeature1” in clone1:
$ cd clone1 $ git branch * master $ git branch newfeature1 $ git branch * master newfeature1 $ git checkout newfeature1 Switched to branch 'newfeature1' $ git branch master * newfeature1
The repository is now point to branch newfeature1. Add a new file to the repository and commit changes:
$ echo "This is new feature" > feature1 $ git add feature1 $ git commit -m "Commit new feature" [newfeature 399cffe] Commit new feature 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 feature1
Switch branch
Continue from above example. Let’s switch between branches and see what happen to the working directory:
$ git branch master * newfeature1 $ ls -a . .. .git feature1 readme $ git checkout master Switched to branch 'master' $ ls -a . .. .git readme
When switch branch from “newfeature1” to “master”, file “feature1” that was committed in “newfeature1” won’t appear in branch “master”.
List branches in repository
To list existing local branches:
$ git branch
* master
newfeature1
Active branch is indicated by * in front.
To list local and remote tracked branch
$ git branch -a * master newfeature1 remotes/origin/master
To list remote tracked branch only:
$ git branch -r origin/master
Merge with Fast Forward
Assume we perform few commits into branch “newfeature1”:
$ echo "changes #1" >> feature1 $ git commit -a -m "commit changes #1" [newfeature1 fc6a399] commit changes #1 1 files changed, 1 insertions(+), 0 deletions(-) $ echo "changes #2" >> feature1 $ git commit -a -m "commit changes #2" [newfeature1 1ea0fda] commit changes #2 1 files changed, 1 insertions(+), 0 deletions(-) $ git log --oneline --graph * 1ea0fda commit changes #2 * fc6a399 commit changes #1 * 048ce34 Commit new feature 1 * 8b60032 first commit
Perform a fast forward merge into master:
$ git checkout master Switched to branch 'master' $ git merge newfeature1 Updating 8b60032..1ea0fda Fast-forward feature1 | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 feature1 $ git log --oneline --graph * 1ea0fda commit changes #2 * fc6a399 commit changes #1 * 048ce34 Commit new feature 1 * 8b60032 first commit
All commit changes from newfeature1 is now merge into master.
Merge without Fast Forward
An advantage with no fast forward merge preserve the branch commit history:
$ git log --oneline --graph * 8b60032 first commit $ git merge --no-ff newfeature1 Merge made by recursive. feature1 | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 feature1 $ git log --oneline --graph * 4725f13 Merge branch 'newfeature1' |\ | * 1ea0fda commit changes #2 | * fc6a399 commit changes #1 | * 048ce34 Commit new feature 1 |/ * 8b60032 first commit
Push Branch to remote
So far all branches are stored in local repository only. You may share the branch with others by pushing it to origin:
$ git branch -a * master newfeature1 remotes/origin/master $ git checkout newfeature1 Switched to branch 'newfeature1' $ git push origin HEAD Total 0 (delta 0), reused 0 (delta 0) To /tmp/test.branch/project.git * [new branch] HEAD -> newfeature1 $ git branch -r origin/master origin/newfeature1
Now we create more branch and push to origin:
$ git branch newfeature2 master $ git checkout newfeature2 Switched to branch 'newfeature2' $ echo "Feature 2" > feature2 $ git branch feature3 master newfeature1 * newfeature2 $ git add feature2 $ git commit -m "commit feature 2" [newfeature2 ef39e45] commit feature 2 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 feature2 $ git push origin HEAD Total 0 (delta 0), reused 0 (delta 0) To /tmp/test.branch/project.git * [new branch] HEAD –> newfeature2 $ git branch newfeature3 master $ git checkout newfeature3 Switched to branch 'newfeat $ echo "Feature 3" > feature3 $ git add feature3 $ git commit -m "commit feature 3" [newfeature3 ec1da8d] commit feature 3 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 feature3 $ git push origin HEAD Counting objects: 7, done. Compressing objects: 100% (4/4), done. Writing objects: 100% (6/6), 512 bytes, done. Total 6 (delta 1), reused 0 (delta 0) Unpacking objects: 100% (6/6), done. To /tmp/test.branch/project.git * [new branch] HEAD –> newfeature3
We have these branches now both in local and origin repositories:
$ git branch -a master newfeature1 * newfeature2 newfeature3 remotes/origin/master remotes/origin/newfeature1 remotes/origin/newfeature2 remotes/origin/newfeature3
Fetch Remote Branch
Let’s switch to clone2:
$ cd clone2 $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master $ git remote show origin * remote origin Fetch URL: /tmp/test.branch/project.git Push URL: /tmp/test.branch/project.git HEAD branch: master Remote branches: master tracked newfeature1 new (next fetch will store in remotes/origin) newfeature2 new (next fetch will store in remotes/origin) newfeature3 new (next fetch will store in remotes/origin) Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': master pushes to master (up to date)
Notice that there are 3 new branches: newfeature1, newfeature2 and newfeature3 in origin.
Now fetch from origin,
$ git fetch From /tmp/test.branch/project * [new branch] newfeature1 -> origin/newfeature1 * [new branch] newfeature2 -> origin/newfeature2 * [new branch] newfeature3 -> origin/newfeature3 $ git branch -a * master remotes/origin/HEAD -> origin/master remotes/origin/master remotes/origin/newfeature1 remotes/origin/newfeature2 remotes/origin/newfeature3 $ git remote show origin * remote origin Fetch URL: /tmp/test.branch/project.git Push URL: /tmp/test.branch/project.git HEAD branch: master Remote branches: master tracked newfeature1 tracked newfeature2 tracked newfeature3 tracked Local branch configured for 'git pull': master merges with remote master Local ref configured for 'git push': master pushes to master (up to date)
To have a look on the remote branch newfeature2, use git checkout:
$ git checkout origin/newfeature2 Note: checking out 'origin/newfeature2'. 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 c47ec36... This is new feature 2 $ ls -a . .. .git feature2 readme
The checkout origin/newfeature2 will switch local repository to “detached HEAD”. A detached HEAD doesn’t belongs to any branch:
$ git branch -a * (no branch) master remotes/origin/master remotes/origin/newfeature1 remotes/origin/newfeature2 remotes/origin/newfeature3
You shouldn’t commit any changes that doesn’t belong to a named branch or else others will have problems merging with the changes. Instead you should name a branch or checkout local branch before commit any changes:
$ git checkout newfeature2
Branch newfeature2 set up to track remote branch newfeature2 from origin.
Switched to a new branch 'newfeature2'
$ git branch -a
master
* newfeature2
remotes/origin/master
remotes/origin/newfeature1
remotes/origin/newfeature2
remotes/origin/newfeature3
Delete local branch
For branch that you never push to origin, you may delete it as follow:
$ git branch
master
* newfeature1
$ git branch -d newfeature1
error: Cannot delete the branch 'newfeature1' which you are currently on.
Active branch is not allow to delete. You may switch to other branch first
$ git checkout master
Switched to branch 'master'
$ git branch -d newfeature1
error: The branch 'newfeature1' is not fully merged.
If you are sure you want to delete it, run 'git branch -D newfeature1'.
$ git branch -D newfeature1
Deleted branch newfeature1 (was 201bb22).
$ git branch
* master
You can’t delete branch using “-d” if it is not merged with others. To force delete, use “-D” option.
Delete remote tracked branch
Assume the repository has the following branches:
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/newfeature1
remotes/origin/newfeature2
remotes/origin/newfeature3
$ git remote show origin
* remote origin
Fetch URL: /tmp/test.branch/project.git
Push URL: /tmp/test.branch/project.git
HEAD branch: master
Remote branches:
master tracked
newfeature1 tracked
newfeature2 tracked
newfeature3 tracked
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
Delete a remote tracked branch:
$ git branch -d -r origin/newfeature3
Deleted remote branch origin/newfeature3 (was ec1da8d).
$ git branch -a
* master
remotes/origin/HEAD -> origin/master
remotes/origin/master
remotes/origin/newfeature1
remotes/origin/newfeature2
$ git remote show origin
* remote origin
Fetch URL: /tmp/test.branch/project.git
Push URL: /tmp/test.branch/project.git
HEAD branch: master
Remote branches:
master tracked
newfeature1 tracked
newfeature2 tracked
newfeature3 new (next fetch will store in remotes/origin)
Local branch configured for 'git pull':
master merges with remote master
Local ref configured for 'git push':
master pushes to master (up to date)
No comments:
Post a Comment