Exercise 2 - Non-linear workflow with branches
In this exercise, you will learn how to work with branches. You will create branches, merge them and resolve a conflict.
- Create a branch
- Make changes on a branch
- Switching between branches
- Another branch
- Merge
- Reset a branch
- Merge with an extra commit
- Merge with conflict
- Resolve conflicts
Create a branch
We want to take some further notes from the workshop. However, we will now work on different branches and start with the chapter on how to inspect the history. First, create a new branch inspect-history
git branch inspect-history
Let's list the branches we have now
git branch
Output
inspect-history
* main
Fine, but we are still on main
. Switch to inspect-history
and list branches again
git switch inspect-history
git branch
Output
* inspect-history
main
The
switch
command is relatively new in Git. On older versions, you have to usecheckout
instead. The commandcheckout
can do different things, depending on the context and the arguments. To reduce ambiguities, in newer versions of Gitswitch
can be used instead ofcheckout
to switch between branches, andrestore --staged
to un-stage changes.
We now have two branches and are currently on inspect-history
. When using git log
, you will see that both branches point to the same commit.
git log
Output
commit 1860049c5afd2ffed4661e8e36745aec3da57183 (HEAD -> inspect-history, main)
Author: ... <...@ufz.de>
Date: Wed Jan 27 20:27:02 2021 +0100
added linear workflow
commit d8d9072990da891df3624358b7a8fc473afb57f8
Author: ... <...@ufz.de>
Date: Wed Jan 27 20:25:35 2021 +0100
initial commit
BTW, HEAD
shows where you currently are.
There is also a shortcut that creates a branch and switches to it immediately
git switch -c inspect-history
Make changes on a branch
Create a new file inspecting.md
echo.> inspecting.md
Fill it with some content, e.g.
# Inspecting
## Inspect the history
```
git log
```
## Inspecting commits
```
git show
git show 3cda487
git show README.md
```
Save your changes.
Link it in README.md
and save again.
# Git Workshop
Content
* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* ...
Now, commit as usual
git status
git diff
git add README.md inspecting.md
git status
git commit -m "added page on inspecting the history"
Let's view the history again
git log
For a more compact view, use
git log --oneline
Output
eba0f8f (HEAD -> inspect-history) added page on inspecting the history
1860049 (main) added linear workflow
d8d9072 initial commit
You will see that branch inspect-history
is now one commit ahead of main
. I.e. it moved along with our changes, while main
did not.
Switching between branches
With Git, it is possible to work on multiple branches in parallel.
Using switch
, we can simply switch between branches.
Observe the content of your project folder. There are now three Markdown files.
Switch to main
and see the folder content again
git switch main
Now, the file inspecting.md
isn't there anymore.
When we switched to main
, Git replaced the files in our working copy with the version referenced by main
.
Switch to branch inspect-history
again to see that the working copy changes again and inspecting.md
is back again.
git switch inspect-history
Another branch
We now make some parallel edits on an additional branch.
First, switch to main
again, as we want to start from there rather than from inspect-history
git switch main
Create another branch amending-commits
where we will take notes on that aspect
git switch -c amending-commits
Create a new file amending.md
echo.> amending.md
Fill it the following content (and save...)
# Amending commits
```
git status
git diff
git add README.md
git commit --amend
```
Link the file in README.md
# Git Workshop
Content
* [Linear workflow](linear-workflow.md)
* [Amending commits](amending.md)
* ...
You may notice that the link to inspecting.md
has gone. This is because we went back to branch main
, which does not contain that change.
Commit as usual
git status
git diff
git add README.md amending.md
git status
git commit -m "added page on amending commits"
Let's inspect again what we have, with option --oneline
for a more compact view
git log --oneline
Output
0639ed4 (HEAD -> amending-commits) added page on amending commits
1860049 (main) added linear workflow
d8d9072 initial commit
You may be surprised where branch inspect-history
has gone. This is because by default, Git only shows what is part of the history of the current state, which inspect-history
is not. To see the entire history as a (directed acyclic) graph, add options --all
and --graph
git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 (main) added linear workflow
* d8d9072 initial commit
You should see the entire graph now, and that we have diverged from main
in two different directions.
Merge
When the work on a branch is completed, it can be merged back into main
. To merge, you need to be on the branch you want to merge the other branch into. So we switch to main
git switch main
Now, merge amending-commits
into the current branch main
git merge amending-commits
Output
Updating 1860049..0639ed4
Fast-forward
README.md | 2 +-
amending.md | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
create mode 100644 amending.md
Inspect the graph again
git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> main, amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 added linear workflow
* d8d9072 initial commit
Now, main
and amending-commits
point to the same commit, but somehow our branching topology has gone. This is because Git makes a so-called "fast-forward" merge in case there are no conflicts. We can prevent that with the option --no-ff
. But first, we have to undo the merge.
Reset a branch
To bring main
back to the state before the merge, we make a hard reset to the previous commit (use the correct hash, the 3rd counted from the top!)
git reset --hard 1860049
Output
HEAD is now at 1860049 added linear workflow
Inspect again to see that we have what we had before the merge
git log --graph --oneline --all
Output
* 0639ed4 (HEAD -> amending-commits) added page on amending commits
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 (main) added linear workflow
* d8d9072 initial commit
Merge with an extra commit
Now, we can merge without "fast-forward"
git merge amending-commits --no-ff
Output
Merge made by the 'recursive' strategy.
README.md | 2 +-
amending.md | 8 ++++++++
2 files changed, 9 insertions(+), 1 deletion(-)
create mode 100644 amending.md
Inspect again to see that the branching topology is preserved now
git log --graph --oneline --all
Output
* e25d3cc (HEAD -> main) Merge branch 'amending-commits'
|\
| * 0639ed4 (amending-commits) added page on amending commits
|/
| * eba0f8f (inspect-history) added page on inspecting the history
|/
* 1860049 added linear workflow
* d8d9072 initial commit
Further, a new commit was created, with an automatic message (Merge branch 'amending-commits'
)
Merge with conflict
We can now try to also merge branch inspect-history
git merge inspect-history --no-ff
Output
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
Git says that automatic merging failed due to a conflict in README.md
, and that we should resolve the conflict and then commit. This is also a reminder to always read Git's output carefully.
To get some more insights, check the status
git status
Output
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
(use "git merge --abort" to abort the merge)
Changes to be committed:
new file: inspecting.md
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: README.md
Again, read carefully! We have unmerged paths.
Further, is says we can resolve the conflicts and commit, or abort.
merge
is an example of a modal command, i.e. we have to commit or abort the merge before we can continue to use Git normally.
For practice, we abort the merge and view the status:
git merge --abort
git status
Output
On branch main
nothing to commit, working tree clean
That was for practice. Now let's merge again and resolve the conflict.
git merge inspect-history --no-ff
Output
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Automatic merge failed; fix conflicts and then commit the result.
We get the same message as before: that automatic merging failed due to a conflict in README.md
.
Resolve conflicts
Open file README.md
. It has the following content
# Git Workshop
Content
* [Linear workflow](linear-workflow.md)
<<<<<<< HEAD
* [Amending commits](amending.md)
=======
* [Inspecting](inspecting.md)
>>>>>>> inspect-history
* ...
The content between <<<<<<< HEAD
and >>>>>>> inspect-history
is where the conflict is, with the first part on main
(our current HEAD
), and the second part on inspect-history
. Resolve the conflict and make the file look like this
# Git Workshop
Content
* [Linear workflow](linear-workflow.md)
* [Inspecting](inspecting.md)
* [Amending commits](amending.md)
Now that the conflict is resolved we can stage as usual
git status
git diff
git add README.md
git status
Output
On branch main
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: README.md
new file: inspecting.md
Git tells us that all conflicts are fixed, but we are still merging. We do what it suggests and commit
git commit
Leave the message in the popup as is and close it.
Through the commit, we finished the merge and are now no longer in "merge mode". Confirm through checking the status
git status
Output
On branch main
nothing to commit, working tree clean
Inspect the graph again
git log --graph --oneline --all
Output
* fc527c5 (HEAD -> main) Merge branch 'inspect-history'
|\
| * eba0f8f (inspect-history) added page on inspecting the history
* | e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 (amending-commits) added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit
We see two nicely merged branches.
To finish our work, we should delete the merged branches. They are only pointers and not needed anymore. The topology will remain untouched by deleting them
git branch --delete amending-commits
git branch --delete inspect-history
And, a final check that everything worked as expected
git log --graph --oneline --all
* fc527c5 (HEAD -> main) Merge branch 'inspect-history'
|\
| * eba0f8f added page on inspecting the history
* | e25d3cc Merge branch 'amending-commits'
|\ \
| |/
|/|
| * 0639ed4 added page on amending commits
|/
* 1860049 added linear workflow
* d8d9072 initial commit
Continue with Exercise 3