GIT Part-4


Knowing in advance which version to stay with
It may happen that we know beforehand which version we want to choose in case of conflicts. In these cases, we can tell Git which version use, to make it apply it directly.

To do this, we have to pass the -X option to merge, indicating which version use:

git merge -X <ours|theirs> <branch-name>

So, for using HEAD version, we would have to use ours option; instead, for using the version that is not HEAD‘s, theirshas to be passed.
That is, the following:


git merge -X ours second-branch

Would leave the file as is shown:
1
2
3
one
two
three
And, the following:

git merge -X theirs second-branch

As it follows:
1
2
3
one
two
three (from second-branch)

Checking differences
Git allows to check the differences between distinct points in the history. This is done with diff option.

Interpreting the differences
Before seeing what differences we can look at, firstly we have to understand how the differences are shown.

Let’s see a sample output of a difference between the same file:


diff --git a/README.txt b/README.txt
index 31325b6..55e8d58 100644
--- a/README.txt
+++ b/README.txt
@@ -1,2 +1,2 @@
-This is
-the original file
+This file
+has been modified

Here, a is the a previous version of the file, and b the current version.
The third and fourth line identifies each letter with a - or + symbol.
That @@ -1,2 +1,2 @@ is called “hunk header”. This identifies the chunks of code that actually have changed, not showing the common parts for both versions.

The format is the following:

@@ <previous><from-line>,<number-of-lines> <current>,<from-line><number-of-lines>

In this case:
“previous”: identified with -, corresponding to a.
“from-line”: the line number from where the changes start.
“number-of-lines”: the number of lines shown.
“current”: identified with +, corresponding to b.

Finally, which lines are subtracted, and which added, are shown. In this case, two lines have been subtracted from the line (those preceded with -), and other two have been added (preceded with +).

Differences between working directory and last commit
One common use is to check the differences between the working directory and the last commit. For this, is enough to execute:

git diff

Which will show the difference for every file. We can specify also specific files:


git diff <file1> <file2>

Differences between exact points in history
We can look for differences with:
SHA1 id
Branch names
HEAD
Tags
Being combinable between them.
The syntax is the following:

git diff <original>..<modified>

For example, the following would show the changes that have been applied to dev branch, compared to a v1.0 tag:


git diff v1.0..dev


Tagging important points:
Tagging is one of the nicest features of Git, since allows to mark important points in the repository history, in a very easy way. Usually, tags are used to mark releases, not only for stable releases, but also for under-development or incomplete releases, such as:
Alpha
Beta
Release candidate (rc)

Creating a tag is so simple, we just have to situate the HEAD in the point we want to tag, and just specify the tag name with the tag option:

git tag -a <tag-name>

For example:
git tag -a v0.1-beta1
Then, we will be asked to type a message for the tag. Typically, the changes made from last tag are specified.
As when committing, we can specify the tag message inline, with -m flag:

git tag -a v0.1 -m 'v0.1 stable release, changes from...'

Take into account that the tag names cannot be repeated in a repository.

Undoing and deleting things
Git also allows to undo and modify some things in the history. In this section we will see what can be done, and how.

Modifying the last commit
Is quite common to want to modify the last commit, for example, when just a line of code has to be added; or even to modify the update message, without changing any file.

For that, Git has the --amend flag for commit command:

git commit --amend

This is just the same as committing, but, instead of a new commit object, the last one of that branch will be overwritten.

Discarding uncommitted changes
This is for, after a commit, when we keep developing, we think that we have taken an incorrect path, and we want to reset the changes, returning to the last commit’s state.

For this, the command used is checkout, as for moving between branches. But, when specifying a file, this gets reseted to the state of the last commit.
For example:





echo 'one' > test.txt
git add test.txt
git commit -m 'commit one'
echo 'two' > test.txt
git checkout test.txt # The content of test.txt is now 'one'.

Deleting commits
Usually, we want to delete commits when we don’t want to leave any record of an embarrassing commit, or just for removing useless changes.
This is achieved moving the branch or HEAD pointers. Moving the pointers to previous commits makes the commits remaining ahead get “lost”, unlinked from the linked list. To move them, reset command is used.

There are two ways of making a reset: not touching the working directory (soft reset, --soft flag), or resetting it too (hard reset, --hard flag). That is, if you make a soft reset, the commit(s) will be removed, but the modifications saved in that/those commit(s) will remain; and a hard reset, won’t leave change made in the commit(s). If no flag is specified, the reset will be done softly.

Let’s start resetting things. The following command would remove the last commit, i.e., the commit where HEAD is pointing to:


git reset --hard HEAD~

The ~ character is for indicating an ancestor. Used once, indicates the immediate parent; twice, the grandparent; and so on. But, instead of typing ~ n times, we can specify the n ancestors that we want to remove:


git reset --hard HEAD~3

Which would remove the last 3 commits.

You may have noticed that this may cause conflicts with those commits with more than one ancestor, i.e., the result of a not fast-forwarded merge. Well, it doesn’t cause any problem: the followed parent using HEAD~ is always the first one. But there’s a way to decide which of the common parents follow: ^, followed by the parent number. So, the following:


git reset --hard HEAD~2^2

Would remove the previous two commits, but taking the path of the second ancestor.

Even if it is possible to specify which ancestor path follow, is recommended to always use the syntax for first ancestor (only ~) since it’s easier, even if more commands would be required (since you would have to checkout the different branches to update HEAD position).

Deleting tags
Deleting tags is so simple:


git tag -d <tag-name>


<< Previous                                                                                                                            Next >>



No comments:

Post a Comment