From f8ded1604a2f64a6d4766fcab85234736940dc92 Mon Sep 17 00:00:00 2001 From: Scott Chacon Date: Fri, 4 Jun 2010 13:24:39 +0200 Subject: [PATCH] branch, checkout, merge docs --- _layouts/reference.html | 2 +- branching/index.html | 468 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 469 insertions(+), 1 deletion(-) create mode 100644 branching/index.html diff --git a/_layouts/reference.html b/_layouts/reference.html index 0c91d1d..183dd2b 100755 --- a/_layouts/reference.html +++ b/_layouts/reference.html @@ -58,8 +58,8 @@

Branching and Merging

diff --git a/branching/index.html b/branching/index.html new file mode 100644 index 0000000..3ece42d --- /dev/null +++ b/branching/index.html @@ -0,0 +1,468 @@ +--- +layout: reference +--- + +
+

+ + book + + Branching and Merging +

+
+

Branching in Git is one of my favorite features. If you have used other + version control systems, it's probably helpful to forget most of what you + think about branches - in fact, it may be more helpful to think of them + practically as contexts since that is how you will most often be + using them. When you checkout different branches, you change contexts + that you are working in and you can quickly context-switch back and forth + between several different branches. +

+ +

+ In a nutshell you can create a branch with + git branch (branchname), switch into that context with + git checkout (branchname), record commit snapshots while + in that context, then can switch back and forth easily. When you switch + branches, Git replaces your working directory with the snapshot of the + latest commit on that branch so you don't have to have multiple directories + for multiple branches. You merge branches together with + git merge. You can easily merge multiple times from the same + branch over time, or alternately you can choose to delete a branch + immediately after merging it. +

+ +
+
+ +
+

+ + docs   + book + + git branch + list, create and manage working contexts +

+ +
+ +

+ + docs   + book + + git checkout + switch to a new branch context +

+ +
+

The git branch command is a general branch management tool + for Git and can do several different things. We'll cover the basic ones + that you'll use most - listing branches, creating branches and deleting + branches. We will also cover basic git checkout here which + switches you between your branches. +

+ +

+ git branch + list your available branches +

+ +

Without arguments, git branch will list out the local + branches that you have. The branch that you are currently working on will + have a star next to it and if you have + coloring turned on, + will show the current branch in green. +

+ +
+$ git branch
+* master
+
+ +

This means that we have a 'master' branch and we are currently on it. + When you run git init it will automatically create a 'master' + branch for you by default, however there is nothing special about the name - + you don't actually have to have a 'master' branch but since it's the default + that is created, most projects do. +

+ +

+ git branch (branchname) + create a new branch +

+ +

So let's start by creating a new branch and switching to it. You can do + that by running git branch (branchname). + +

+$ git branch testing
+$ git branch
+* master
+  testing
+
+ +

Now we can see that we have a new branch. When you create a branch this + way it creates the branch at your last commit so if you record some commits + at this point and then switch to 'testing', it will revert your working + directory context back to when you created the branch in the first place - + you can think of it like a bookmark for where you currently are. Let's see + this in action - we use git checkout (branch) to switch the + branch we're currently on. +

+ +
+$ ls
+README   hello.rb
+$ echo 'test content' > test.txt
+$ echo 'more content' > more.txt
+$ git add *.txt
+$ git commit -m 'added two files'
+[master 8bd6d8b] added two files
+ 2 files changed, 2 insertions(+), 0 deletions(-)
+ create mode 100644 more.txt
+ create mode 100644 test.txt
+$ ls
+README   hello.rb more.txt test.txt
+$ git checkout testing
+Switched to branch 'testing'
+$ ls
+README   hello.rb
+
+ +

So now we can see that when we switch to the 'testing' branch, our new + files were removed. We could switch back to the 'master' branch and see + them re-appear.

+ +
+$ ls
+README   hello.rb
+$ git checkout master
+Switched to branch 'master'
+$ ls
+README   hello.rb more.txt test.txt
+
+ +

+ git checkout -b (branchname) + create and immediately switch to a branch +

+ +

+ In most cases you will be wanting to switch to the branch immediately, so + you can do work in it and then merging into a branch that only contains + stable work (such as 'master') at a later point when the work in your new + context branch is stable. You can do this pretty easily with + git branch newbranch; git checkout newbranch, but Git gives + you a shortcut for this: git checkout -b newbranch. +

+ +
+$ git branch
+* master
+$ ls
+README   hello.rb more.txt test.txt
+$ git checkout -b removals
+Switched to a new branch 'removals'
+$ git rm more.txt 
+rm 'more.txt'
+$ git rm test.txt 
+rm 'test.txt'
+$ ls
+README   hello.rb
+$ git commit -am 'removed useless files'
+[removals 8f7c949] removed useless files
+ 2 files changed, 0 insertions(+), 2 deletions(-)
+ delete mode 100644 more.txt
+ delete mode 100644 test.txt
+$ git checkout master
+Switched to branch 'master'
+$ ls
+README   hello.rb more.txt test.txt
+
+ +

You can see there how we created a branch, removed some of our files + while in the context of that branch, then switched back to our main branch + and we see the files return. Branching safely isolates work that we do into + contexts we can switch between.

+ +

+ If you start on work it is very useful to + always start it in a branch (because it's fast and easy to do) and then + merge it in and delete the branch when you're done. That way if what you're + working on doesn't work out you can easily discard it and if you're forced + to switch back to a more stable context your work in progress is easy to put + aside and then come back to.

+ +

+ git branch -d (branchname) + delete a branch +

+ +

If we want to delete a branch (such as the 'testing' branch in the + previous example, since there is no unique work on it), + we can run git branch -d (branch) to remove it. + +

+$ git branch
+* master
+  testing
+$ git branch -d testing
+Deleted branch testing (was 78b2670).
+$ git branch
+* master
+
+ +

+ In a nutshell you use git branch to list your + current branches, create new branches and delete unnecessary or + already merged branches. +

+ +
+
+ +
+

+ + docs   + book + + git merge + merge a branch context into your current one +

+ +
+

Once you have work isolated in a branch, you will eventually want to + incorporate it into your main branch. You can merge any branch into your + current branch with the git merge command. Let's take as a + simple example the 'removals' branch from above. If we create a branch + and remove files in it and commit our removals to that branch, it is + isolated from our main ('master', in this case) branch. To include those + deletions in your 'master' branch, you can just merge in the 'removals' + branch. +

+ +
+$ git branch
+* master
+  removals
+$ ls
+README   hello.rb more.txt test.txt
+$ git merge removals
+Updating 8bd6d8b..8f7c949
+Fast-forward
+ more.txt |    1 -
+ test.txt |    1 -
+ 2 files changed, 0 insertions(+), 2 deletions(-)
+ delete mode 100644 more.txt
+ delete mode 100644 test.txt
+$ ls
+README   hello.rb
+
+ +

+ more complex merges +

+ +

Of course, this doesn't just work for simple file additions and + deletions. Git will merge file modifications as well - in fact, it's very + good at it. For example, let's see what happens when we edit a file in + one branch and in another branch we rename it and then edit it and then + merge these branches together. Chaos, you say? Let's see. +

+ +
+$ git branch
+* master
+$ cat hello.rb 
+class HelloWorld
+  def self.hello
+    puts "Hello World"
+  end
+end
+
+HelloWorld.hello
+
+ +

So first we're going to create a new branch named 'change_class' and + switch to it so your class renaming changes are isolated. I'm going to + change each instance of 'HelloWorld' to 'HiWorld'.

+ +
+$ git checkout -b change_class
+M hello.rb
+Switched to a new branch 'change_class'
+$ vim hello.rb 
+$ head -1 hello.rb 
+class HiWorld
+$ git commit -am 'changed the class name'
+[change_class 3467b0a] changed the class name
+ 1 files changed, 2 insertions(+), 4 deletions(-)
+
+ +

So now I've committed the class renaming changes to the 'change_class' + branch. If I now switch back to the 'master' branch my class name will + revert to what it was before I switched branches. Here I can change + something different (in this case the printed output) and at the same + time rename the file from hello.rb to ruby.rb. + + +

+$ git checkout master
+Switched to branch 'master'
+$ git mv hello.rb ruby.rb
+$ vim ruby.rb 
+$ git diff
+diff --git a/ruby.rb b/ruby.rb
+index 2aabb6e..bf64b17 100644
+--- a/ruby.rb
++++ b/ruby.rb
+@@ -1,7 +1,7 @@
+ class HelloWorld
+ 
+   def self.hello
+-    puts "Hello World"
++    puts "Hello World from Ruby"
+   end
+ 
+ end
+$ git commit -am 'added from ruby'
+[master b7ae93b] added from ruby
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+ rename hello.rb => ruby.rb (65%)
+
+ +

Now those changes are recorded in my 'master' branch. Notice that the + class name is back to 'HelloWorld', not 'HiWorld'. Now I want to + incorporate the 'HiWorld' change so I can just merge in my 'change_class' + branch. However, I've changed the name of the file since I branched, + what will Git do?

+ +
+$ git branch
+  change_class
+* master
+$ git merge change_class
+Renaming hello.rb => ruby.rb
+Auto-merging ruby.rb
+Merge made by recursive.
+ ruby.rb |    6 ++----
+ 1 files changed, 2 insertions(+), 4 deletions(-)
+$ cat ruby.rb
+class HiWorld
+  def self.hello
+    puts "Hello World from Ruby"
+  end
+end
+
+HiWorld.hello
+
+ +

Well, it will just figure it out. Notice that I had no merge conflicts + and the file that had been renamed now has the 'HiWorld' class name change + that was done in the other branch. Pretty cool.

+ +

+ merge conflicts +

+ +

So, Git merges are magical, we never ever have to deal with merge + conflicts again, right? Not quite. In situations where the same block + of code is edited in different branches there is no way for a computer + to figure it out, so it's up to us. Let's see another example of changing + the same line in two branches. +

+ +

+$ git branch
+* master
+$ git checkout -b fix_readme
+Switched to a new branch 'fix_readme'
+$ vim README 
+$ git commit -am 'fixed readme title'
+[fix_readme 3ac015d] fixed readme title
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+ +

Now we have committed a change to one line in our README file in a + branch. Now let's change the same line in a different way back on + our 'master' branch.

+ +
+$ git checkout master
+Switched to branch 'master'
+$ vim README 
+$ git commit -am 'fixed readme title differently'
+[master 3cbb6aa] fixed readme title differently
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+ +

Now is the fun part - we will merge the first branch into our master + branch, causing a merge conflict.

+ +
+$ git merge fix_readme
+Auto-merging README
+CONFLICT (content): Merge conflict in README
+Automatic merge failed; fix conflicts and then commit the result.
+$ cat README 
+<<<<<<< HEAD
+Many Hello World Examples
+=======
+Hello World Lang Examples
+>>>>>>> fix_readme
+
+This project has examples of hello world in
+nearly every programming language.
+
+ +

You can see that Git inserts standard merge conflict markers, much like + Subversion, into files when it gets a merge conflict. Now it's up to us + to resolve them. We will do it manually here, but check out + git mergetool + if you want Git to fire up a graphical mergetool + (like kdiff3, emerge, p4merge, etc) instead. +

+ +
+$ vim README   # here I'm fixing the conflict
+$ git diff
+diff --cc README
+index 9103e27,69cad1a..0000000
+--- a/README
++++ b/README
+@@@ -1,4 -1,4 +1,4 @@@
+- Many Hello World Examples
+ -Hello World Lang Examples
+++Many Hello World Lang Examples
+  
+  This project has examples of hello world in
+
+ +

A cool tip in doing merge conflict resolution in Git is that if you + run git diff, it will show you both sides of the conflict + and how you've resolved it as I've shown here. Now it's time to mark + the file as resolved. In Git we do that with git add - + to tell Git the file has been resolved, you have to stage it.

+ +
+$ git status -s
+UU README
+$ git add README 
+$ git status -s
+M  README
+$ git commit 
+[master 8d585ea] Merge branch 'fix_readme'
+
+ +

And now we've successfully resolved our merge conflict and committed + the result.

+ +
+ +
+ +

On to Sharing and Updating Projects »

+