Professional Documents
Culture Documents
GIT/Gerrit know-how
GIT training agenda
Introduction
Setup & First commit
Three states & Basic workflow
History and old revisions
Fix mistakes
Undoing local changes
Undoing staged changes
Undoing committed changes
Amending changes
Git internals
Branching
Resolving conflicts
Merge
Rebase
Cherry-pick
Rewriting history
Multiple repositories
Tips & tricks
Branching
Creating branch (local)
Navigating branches
Merging vs Rebasing
Resolving conflicts
It‟s time to do a major rewrite of the hello world functionality. Since this
might take awhile, you‟ll want to put these changes into a separate branch
to isolate them from changes in master.
lukic@gtv02-lin-$ git checkout -b dev-lukic
Switched to a new branch 'dev-lukic‘
lukic@gtv02-lin-$ git branch
* dev-lukic
master
lukic@gtv02-lin-$ git status
# On branch dev-lukic
nothing to commit, working directory clean
lukic@gtv02-lin-$ vi src/main.c
lukic@gtv02-lin-$ git add src/main.c
lukic@gtv02-lin-$ git commit -m "First commit on dev-lukic branch"
[dev-lukic 4b3b71a] First commit on dev-lukic branch
1 file changed, 1 insertion(+)
Now, our small project have two branches (master and dev-lukic),
where dev-lukic is “ahead” of master by one commit. Lets use git
log command to examine status on both branches:
master branch
lukic@gtv02-lin-$ git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short master
* 756aa57 2014-05-24 | Moved main.c to src directory (master) [Nemanja Lukic]
* 459273f 2014-05-24 | My fourth commit [Nemanja Lukic]
* 9492649 2014-05-24 | My third commit (tag: v1) [Nemanja Lukic]
* 6cfaf1c 2014-05-24 | My second commit (tag: v1-beta) [Nemanja Lukic]
* 4ae7eb5 2014-05-24 | My first commit [Nemanja Lukic]
dev-lukic
lukic@gtv02-lin-$ git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short dev-lukic
* 4b3b71a 2014-05-24 | First commit on dev-lukic branch (HEAD, dev-lukic) [Nemanja Lukic]
* 756aa57 2014-05-24 | Moved main.c to src directory (master) [Nemanja Lukic]
* 459273f 2014-05-24 | My fourth commit [Nemanja Lukic]
* 9492649 2014-05-24 | My third commit (tag: v1) [Nemanja Lukic]
* 6cfaf1c 2014-05-24 | My second commit (tag: v1-beta) [Nemanja Lukic]
* 4ae7eb5 2014-05-24 | My first commit [Nemanja Lukic]
CL6 dev-lukic
How to do it?
Using git rebase command, you can put all work from dev-lukic “on-
top” of current state of master branch:
lukic@gtv02-lin-$ git checkout dev-lukic
Switched to branch 'dev-lukic'
lukic@gtv02-lin-$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: First commit on dev-lukic branch
lukic@gtv02-lin-$ git log --pretty=format:'%h %ad | %s%d [%an]' --graph --date=short --all
* 22de96b 2014-05-24 | First commit on dev-lukic branch (HEAD, dev-lukic) [Nemanja Lukic]
* fe6efcc 2014-05-24 | Adding Readme file (master) [Nemanja Lukic]
* 756aa57 2014-05-24 | Moved main.c to src directory [Nemanja Lukic]
* 459273f 2014-05-24 | My fourth commit [Nemanja Lukic]
* 9492649 2014-05-24 | My third commit (tag: v1) [Nemanja Lukic]
* 6cfaf1c 2014-05-24 | My second commit (tag: v1-beta) [Nemanja Lukic]
* 4ae7eb5 2014-05-24 | My first commit [Nemanja Lukic]
X CL6' dev-lukic
Second, lets add one more branch (dev-lukic2), witch starts from
master, with one commit:
lukic@gtv02-lin-$ git checkout master
Switched to branch 'master'
lukic@gtv02-lin-$ git checkout -b dev-lukic2
Switched to a new branch 'dev-lukic2'
lukic@gtv02-lin-$ vi src/main.c
lukic@gtv02-lin-$ git add src/main.c
lukic@gtv02-lin-$ git commit -m "First commit on dev-lukic2 branch"
[dev-lukic2 e300f98] First commit on dev-lukic2 branch
1 file changed, 1 insertion(+)
lukic@gtv02-lin-$ git hist --all
* e300f98 2014-05-25 | First commit on dev-lukic2 branch (HEAD, dev-lukic2) [Nemanja Lukic]
| * a0ec4c3 2014-05-25 | Second commit on dev-lukic branch (dev-lukic) [Nemanja Lukic]
| * 22de96b 2014-05-24 | First commit on dev-lukic branch [Nemanja Lukic]
|/
* fe6efcc 2014-05-24 | Adding Readme file (master) [Nemanja Lukic]
* 756aa57 2014-05-24 | Moved main.c to src directory [Nemanja Lukic]
* 459273f 2014-05-24 | My fourth commit [Nemanja Lukic]
* 9492649 2014-05-24 | My third commit (tag: v1) [Nemanja Lukic]
* 6cfaf1c 2014-05-24 | My second commit (tag: v1-beta) [Nemanja Lukic]
* 4ae7eb5 2014-05-24 | My first commit [Nemanja Lukic]
CL9
gitk giggle
Introduction
Setup & First commit
Three states & Basic workflow
History and old revisions
Fix mistakes
Undoing local changes
Undoing staged changes
Undoing committed changes
Amending changes
Git internals
Branching
Resolving conflicts
Merge
Rebase
Cherry-pick
Rewriting history
Multiple repositories
Tips & tricks
CL9
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
Using git diff command we can see what is actually being staged after
git rebase (actual conflict situation):
lukic@gtv02-lin-$ git diff
diff --cc src/main.c
index f8e51d3,b0f48d4..0000000
--- a/src/main.c
+++ b/src/main.c
@@@ -1,5 -1,4 +1,9 @@@
First change!
Second change!
Third change!
++<<<<<<< HEAD
+Change on new branch!
+Second change on new branch!
++=======
+ First commit on dev-lukic2 branch!
++>>>>>>> First commit on dev-lukic2 branch
The first section (<<<<<<< HEAD) is the version of the code on the head of
the dev-lukic branch (on which we are rebasing). The second section
(starting with =======) is the version on the dev-lukic2 branch (from
commit we are rebasing).
Conflict resolution is always manual. You have to decide how to merge file
changes (take from the HEAD, or from local branch, both, or something in
between)
lukic@gtv02-lin-$ git diff lukic@gtv02-lin-$ vi src/main.c
diff --cc src/main.c lukic@gtv02-lin-$ cat src/main.c
index f8e51d3,b0f48d4..0000000 First change!
--- a/src/main.c Second change!
+++ b/src/main.c Third change!
@@@ -1,5 -1,4 +1,9 @@@
First change! => Change on new branch!
Second change on new branch!
First commit on dev-lukic2 branch!
Second change!
Third change!
++<<<<<<< HEAD
+Change on new branch!
+Second change on new branch!
++=======
+ First commit on dev-lukic2 branch!
++>>>>>>> First commit on dev-lukic2 branch
After resolving conflict (in this case, combine changes from the HEAD and
from local change), stage the change, and continue with rebasing process.
Since this new change is “altered” original change, usually it is marked
(with apostrophe) to emphasize this fact.
lukic@gtv02-lin-$ vi src/main.c
lukic@gtv02-lin-$ git add src/main.c
lukic@gtv02-lin-$ git rebase --continue
Applying: First commit on dev-lukic2 branch
CL9'
Merge process
=>
Because the commit on the branch you‟re on (experiment) isn‟t a direct ancestor of the
branch you‟re merging in (master), Git has to do some work.
In this case, Git does a simple three-way merge, using the two snapshots pointed to by the
branch tips and the common ancestor of the two.
This results in a NEW commit, that bridges differences in experiment and master branch
CL9'
CL10
CONFIDENTIAL – Reproduction prohibited without the prior permission of RT-RK 24
GIT training – Rebase vs Merge (3/5)
After rebase, rebased commit can be integrated back into master using merge (but now
fast-forward), or using cherry-pick command:
The final result of the rebase is very similar to the merge. However, the
commit tree is quite different. Rebase command leaves the chain of
commits linear and much easier to read.
When merging two branches, instead of using git merge (with resolving
conflicts, which adds new unnecessary commits), ALWAYS use git
rebase, together with git cherry-pick command.
First, using rebase, put commit on development branch in line with top of
the branch, where you want to merge it. Transform this:
CL9'
CL10
Into this:
CL1 CL5 CL7 master
CL9'
CL10'
After that, you only need to checkout dev-lukic branch, and cherry-
pick CL10‟:
lukic@gtv02-lin-$ git checkout dev-lukic
Switched to branch 'dev-lukic‘
lukic@gtv02-lin-$ git cherry-pick 74c17af
[dev-lukic bf689d7] First commit on dev-lukic3 branch
1 file changed, 1 insertion(+)
Introduction
Setup & First commit
Three states & Basic workflow
History and old revisions
Fix mistakes
Undoing local changes
Undoing staged changes
Undoing committed changes
Amending changes
Git internals
Branching
Resolving conflicts
Merge
Rebase
Cherry-pick
Rewriting history
Multiple repositories
Tips & tricks
What if you suddenly realize that some very old commit needs to be
changed. And, you don‟t want to put commit that will fix it. You want clean
history, so basically you want to change already merged commit.
This is not possible, right? -> NO, it is possible.
You can do this!
Lets see how to update second commit - 6cfaf1c (both change and commit
message):
lukic@gtv02-lin-$ git hist local_dev-lukic3
* 16da2cd 2014-05-25 | Remote branch dev-lukic3 updated (HEAD, local_dev-lukic3) [Nemanja Lukic]
* f1fe903 2014-05-25 | First commit on local branch (origin/dev-lukic3) [Nemanja Lukic]
* 74c17af 2014-05-25 | First commit on dev-lukic3 branch [Nemanja Lukic]
* a0ec4c3 2014-05-25 | Second commit on dev-lukic branch [Nemanja Lukic]
* 22de96b 2014-05-24 | First commit on dev-lukic branch [Nemanja Lukic]
* fe6efcc 2014-05-24 | Adding Readme file (origin/master) [Nemanja Lukic]
* 756aa57 2014-05-24 | Moved main.c to src directory [Nemanja Lukic]
* 459273f 2014-05-24 | My fourth commit [Nemanja Lukic]
* 9492649 2014-05-24 | My third commit (tag: v1) [Nemanja Lukic]
* 6cfaf1c 2014-05-24 | My second commit (tag: v1-beta) [Nemanja Lukic]
* 4ae7eb5 2014-05-24 | My first commit [Nemanja Lukic]
Run rebase with -i parameter, which is SHA1 of the last “good” commit:
lukic@gtv02-lin-$ git rebase -i 4ae7eb5
This opens interactive window, where you can see all commit from last
“good” commit to the top of the current branch, listed chronologically:
pick 6cfaf1c My second commit
pick 9492649 My third commit
pick 459273f My fourth commit
pick 756aa57 Moved main.c to src directory
pick fe6efcc Adding Readme file
pick 22de96b First commit on dev-lukic branch
pick a0ec4c3 Second commit on dev-lukic branch
pick 74c17af First commit on dev-lukic3 branch
pick f1fe903 First commit on local branch
pick 16da2cd Remote branch dev-lukic3 updated
Mark commit you want to change with edit (6cfaf1c), and change the rest
with the reword:
edit 6cfaf1c My second commit
reword 9492649 My third commit
reword 459273f My fourth commit
reword 756aa57 Moved main.c to src directory
reword fe6efcc Adding Readme file
reword 22de96b First commit on dev-lukic branch
reword a0ec4c3 Second commit on dev-lukic branch
reword 74c17af First commit on dev-lukic3 branch
reword f1fe903 First commit on local branch
reword 16da2cd Remote branch dev-lukic3 updated
When you leave editor, you will be in the rebase mode, and pointing to the
commit you marked for editing:
lukic@gtv02-lin-$ git rebase -i 4ae7eb5
Stopped at 6cfaf1c... My second commit
You can amend the commit now, with
Change the commit, and amend the log. Than continue with rebasing:
lukic@gtv02-lin-$ vi main.c
lukic@gtv02-lin-$ git status
# HEAD detached from 4ae7eb5
# You are currently editing a commit while rebasing branch 'local_dev-lukic3' on '4ae7eb5'.
# (use "git commit --amend" to amend the current commit)
# (use "git rebase --continue" once you are satisfied with your changes)
#
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: main.c
#
no changes added to commit (use "git add" and/or "git commit -a")
lukic@gtv02-lin-$ git add main.c
lukic@gtv02-lin-$ git commit --amend
[detached HEAD 4bad84f] My second commit (after interactive rebase)
1 file changed, 1 insertion(+)
lukic@gtv02-lin-$ git rebase --continue
www.rt-rk.com
info@rt-rk.com