Showing posts with label GIT Log. Show all posts
Showing posts with label GIT Log. Show all posts

Thursday, 8 August 2019

GIT LOG COMMAND EXPLAINED WITH EXAMPLES

INTRODUCTION

In our previous articles on working with the git version control system, we explained how to initialize a local git repositoryadd content to it and we also worked with the git add in detail. In this article, we will focus on the git log command. We will understand the significance of the git log command, the information it provides and usage examples. The significance of git log The git log command allows us to read and review a history all the changes and updates that place in a git repository. This is essential in tracking changes that were made to a file. The git log command also provides us the required information to revert to a previous version of the file or at times even recover a deleted file. We will talk in greater detail about reverting to previous versions of files and deleted file recovery in a subsequent article. Information provided by ‘git log’ A typical git log will provide you with information about all the commits made to a git repository since its inception. It contains the following details corresponding to each commit:
  • A commit hash: A SHA1 40 character checksum of the commits’ contents. Since it is generated based on the commit contents it will always be unique.
  • Commit Author metadata: The name and email address of the author of the commit.
  • Commit Date metadata: A date timestamp for the time of the commit.
  • Commit title/message: The description or comment which was written by the author during the git commit operation.
git log command examples: Now that we understand what the git log command is and the various fields of output it contains, let’s a look at a couple of examples to familiarize ourselves with the usage of this command. We would like to point out that git log will probably be one of the most frequently used git related commands that you are likely to come across. Continuing with our repository created in /home/sahil/git/my_first_repo, I’ve made a couple of more commits since we last used it.
Example 1: Basic usage without additional options In the simplest form of using the git log command, we invoke it without any additional options. Given below is an example:
[sahil@linuxnix my_first_repo]$ git log
commit 23c977041acf1730accd0622ad47b71a6a40a32a
Author: Sahil Suri <sahil.suri@example.com>
Date: Fri Mar 9 12:31:20 2018 +0530

Added another line to test.txt

commit a291f69bcdd40b9f9bf409cafe51030ab9b67e38
Author: Sahil Suri <sahil.suri@example.com>
Date: Tue Mar 6 18:30:54 2018 +0530

Added file test.txt nad updated .md files

commit d76dd618aff0358ea0a63a8a67f398ffe231e775
Author: Sahil Suri <sahil.suri@example.com>
Date: Tue Mar 6 18:20:15 2018 +0530

Modified the *.md files
-------------output truncated for brevity
Note: As you continue to work on the repository and make additional commits, the output of the git log command may become too long to fit on a single terminal screen. When this happens the output of the git log command becomes automatically paginated using the less paging utility.
Example 2: Summarized output In case you are not interested in the author and timestamp details for the commit history, you can shorten the git log command output to a summary type output using the –oneline option with the git log command.
[sahil@linuxnix my_first_repo]$ git log --oneline
23c9770 Added another line to test.txt
a291f69 Added file test.txt nad updated .md files
d76dd61 Modified the *.md files
99fa732 Created a new file README1.md
f9849b2 Added a line to README.md
f7eccb7 Added my first file
This gives the first seven characters of the SHA1 hash corresponding to the git commit along with the comment or description message saved with the commit.
Example 3: View only recent commits We can use the git log command to view only the most recent commits by typing how far back in the history we want git to go while displaying its output. In the below example, we instruct git log to limit it’s output and display information about the last two commits only.
[sahil@linuxnix my_first_repo]$ git log -2
commit 23c977041acf1730accd0622ad47b71a6a40a32a
Author: Sahil Suri <sahil.suri@example.com>
Date: Fri Mar 9 12:31:20 2018 +0530

Added another line to test.txt

commit a291f69bcdd40b9f9bf409cafe51030ab9b67e38
Author: Sahil Suri <sahil.suri@example.com>
Date: Tue Mar 6 18:30:54 2018 +0530

Added file test.txt nad updated .md files
Example 4: Filter commits by author This option is useful if you have many people working on the same repository. To use this option, we type git log followed by the keyword author and the authors’ name whom we want to look for. Given below is an example.
[sahil@linuxnix my_first_repo]$ git log --author="Sahil" --oneline
23c9770 Added another line to test.txt
a291f69 Added file test.txt nad updated .md files
d76dd61 Modified the *.md files
99fa732 Created a new file README1.md
f9849b2 Added a line to README.md
f7eccb7 Added my first file
For this repository, since all the commits were made by me, we get the entire commit history.
Example 5: Filter output by the time We can filter the git log command output by time in case we need to view commits made after or before a certain point in time. We use the –after and –before keywords with the git log command followed by the time window generally specified in days. Here are two examples.
[sahil@linuxnix my_first_repo]$ git log --oneline --before 2.days.ago
a291f69 Added file test.txt nad updated .md files
d76dd61 Modified the *.md files
99fa732 Created a new file README1.md
f9849b2 Added a line to README.md
f7eccb7 Added my first file
[sahil@linuxnix my_first_repo]$
[sahil@linuxnix my_first_repo]$ git log --oneline --after 1.day.ago
23c9770 Added another line to test.txt
[sahil@linuxnix my_first_repo]$
In the first example, we view commits that were made more than two days ago and in the second example, we view commits that were made less than a day ago.
Example 6: Filter commits by date range We could also filter the git log command output to view commit messages made during a range of time. In this case, we would use the –after and –before keywords together in the same command. Given below is the syntax for using the git log command to filter its output within a certain date range.
git log --after <date> --before <date>
Given below is an example:
[sahil@linuxnix my_first_repo]$ git log --oneline --before "2018-03-09" --after "2018-03-07"
23c9770 Added another line to test.txt
[sahil@linuxnix my_first_repo]$
In the above example, we filtered the commit messages within the range of 7th March to 9th March for the year 2018.
Example 7: Formatting the git log output We can use the –pretty option with the git log command to significantly modify how the output would appear on the screen. This includes the addition of colors to the output. The syntax for using –pretty with the git log command is as follows:
git log --pretty=format:"<options>"
Let’s take a look at an example.
git log --pretty=format:"Commit Hash: %Cred%H%Creset, Author: %Cblue%aN%Creset, Date: %Cgreen%aD%Creset"
As you may observe the output is neatly formatted and colored which helps make the output more readable.

CONCLUSION

In this article, we explained the importance of the git log command and demonstrated its usage with the help of examples. 

Monday, 7 January 2019

GIT: Understanding Git Log

Git logs allow you to review and read a history of everything that happens to a repository. The history is built using git-log, a simple tool with a ton of options for displaying commit history.

What’s in Log?

A Git log is a running record of commits. A full log has the following pieces:
  • A commit hash (SHA1 40 character checksum of the commits contents). Because it is generated based on the commit contents it is unique.
  • Commit Author metadata: The name and email address of the author of the commit.
  • Commit Date metadata: A date timestamp for the time of the commit
  • Commit title/message: The overview of the commit as written in the commit message.

A Typical Log

Git logs can be whatever you want them to be. Git-log offers dozens and dozens of options but let’s start with the simplest.
git log 
This outputs the most basic log:
commit 98aa8d722bdecc4e56156cfe1a793a4d16848eb8
Author: Ryan Irelan 
Date:   Sat Jan 10 23:26:40 2015 -0600
 
Adding in new homepage
 
Includes the assets needed for Foundation
 
commit dd8d6f587fa24327d5f5afd6fa8c3e604189c8d4
Author: Ryan Irelan 
Date:   Tue Jan 6 20:07:17 2015 -0600
 
added origination declaration at bottom of RSS feed
This is a snippet of the log, showing two commits. We have a commit SHA1 hash, the author, the date, and the commit message, explaining what happened in the commit. This layout is the default look of the log.
Git has something called Commit Limiting to make it easier to narrow down hundreds or thousands of commits to the ones you want to review.

Directory Restricted Log

The default log is great for grabbing a quick look at what just happened in the repository. But it takes up a lot space and you can only see a handful of commits at once.
When I’m developing a project, I sometimes only want to know what happened in a specific directory. Let’s say I’m working on some CSS or Sass and only want to know about changes in my Sass directory. I can get much more specific with git-log and restrict it only to a specific directory.
git log scss
This will only return commits that had changes in the scss directory.

Log by branch

We can use a similar syntax as directory restriction and build a log for just one branch. We only need to specify the branch we want to see.
git log develop
We can clean that up a little by removing any merge commits (which can bulk up the log if there are a lot of merges, like there would be a develop branch.
git log develop --no-merges

Friday, 28 December 2018

GIT: Submodules

Often in a project, you want to include libraries and other resources. The manual way is to simply download the necessary code files, copy them to your project, and commit the new files into your Git repository.
While this is a valid approach, it's not the cleanest one. By casually throwing those library files into your project, we're inviting a couple of problems:
  • This mixes external code with our own, unique project files. The library, actually, is a project of itself and should be kept separate from our work. There's no need to keep these files in the same version control context as our project.
  • Should the library change (because bugs were fixed or new features added), we'll have a hard time updating the library code. Again, we need to download the raw files and replace the original items.
Since these are quite common problems in everyday projects, Git of course offers a solution: Submodules.

Repositories Inside Repositories

A "Submodule" is just a standard Git repository. The only specialty is that it is nestedinside a parent repository. In the common case of including a code library, you can simply add the library as a Submodule in your main project.
A Submodule remains a fully functional Git repository: you can modify files, commit, pull, push, etc. from inside it like with any other repository.
Let's see how to work with Submodules in practice.

Adding a Submodule

In our sample project, we create a new "lib" folder to host this (and future) library code.
$ mkdir lib
$ cd lib
With the "git submodule add" command, we'll add a little Javascript library from GitHub:
$ git submodule add https://github.com/djyde/ToProgress


Let's have a look at what just happened:
  • (1) The command started a simple cloning process of the specified Git repository:
Cloning into 'lib/ToProgress'...
remote: Counting objects: 180, done.
remote: Compressing objects: 100% (89/89), done.
remote: Total 180 (delta 51), reused 0 (delta 0), pack-reused 91
Receiving objects: 100% (180/180), 29.99 KiB | 0 bytes/s, done.
Resolving deltas: 100% (90/90), done.
Checking connectivity... done.

  • (2) Of course, this is reflected in our file structure: our project now contains a new "ToProgess" folder inside the "lib" directory. As you can see from the ".git" subfolder contained herein, this is a fully-featured Git repository.
CONCEPT
It's important to understand that the actual contents of a Submodule are notstored in its parent repository. Only its remote URL, the local path inside the main project and the checked out revision are stored by the main repository.
Of course, the Submodule's working files are placed inside the specified directory in your project - in the end, you want to use the library's files! But they are not part of the parent project's version control contents.

  • (3) A new ".gitmodules" file was created. This is where Git keeps track of our Submodules and their configuration:
[submodule "lib/ToProgress"]
    path = lib/ToProgress
    url = https://github.com/djyde/ToProgress

  • (4) In case you're interested in the inner workings of Git: besides the ".gitmodules" configuration file, Git also keeps record of the Submodule in your local ".git/config" file. Finally, it also keeps a copy of each Submodule's .git repository in its internal ".git/modules" folder.
CONCEPT
Git's internal management of Submodules is quite complex (as you can already guess from all the .gitmodules, .git/config, and .git/modules entries...). Therefore, it's highly recommended not to mess with configuration files and values manually. Please do yourself a favor and always use proper Git commands to manage Submodules.


Let's have a look at our project's status:
$ git status
On branch master
Changes to be committed:
    (use "git reset HEAD ..." to unstage)

    new file:   .gitmodules
    new file:   lib/ToProgress


Git regards adding a Submodule as a modification like any other - and requests you to commit it to the repository:
$ git commit -m "Add 'ToProgress' Javascript library as Submodule"
Congratulations: we've now successfully added a Submodule to our main project! Before we look at a couple of use cases, let's see how you can clone a project that already has Submodules added.

Cloning a Project with Submodules

You already know that a project repository does not contain its Submodules' files; the parent repository only saves the Submodules' configurations as part of version control.
This shows when you clone a project that contains Submodules: by default, the "git clone" command only downloads the project itself. Our "lib" folder, however, would stay empty.
You have two options to end up with a populated "lib" folder (or wherever else you choose to save your Submodules; "lib" is just an example):
  • (a) You can add the "--recurse-submodules" option to "git clone"; this tells Git to also initialize all Submodules when the cloning is finished.
  • (b) If you used a simple "git clone" command without this option, you need to initialize the Submodules afterwards with "git submodule update --init --recursive"

Checking Out a Revision

A Git repository can have countless committed versions, but only one version's files can be in your working directory. Therefore, like with any Git repository, you have to decide which revision of your Submodule shall be checked out.
CONCEPT
Unlike normal Git repositories, Submodules always point to a specific commit - not a branch. This is because the contents of a branch can change over time, as new commits arrive. Pointing at a specific revision, on the other hand, guarantees that the correct code is always present.
Let's say we want to have an older version of our "ToProgress" library in our project. First, we'll have a look at the library's commit history. We change into the Submodule's base folder and call the "log" command:
$ cd lib/ToProgress/
$ git log --oneline --decorate
Before we take a look at the actual history, I'd like to stress an important point: Git commands are context-sensitive! By moving into the Submodule directory on the command line, all Git commands that we perform will be executed in the context of the Submodule, not its parent repository.
Now, in the log output, we spot a commit that is tagged "0.1.1":
83298f7 (HEAD, master) update .gitignore
a3b6186 remove page
ed693b7 update doc
3557a0e (tag: 0.1.1) change version code
2421796 update readme

This is the version we want to have in our project. To start with, we can simply check out this commit:
$ git checkout 0.1.1
Let's see what our parent repository thinks about all this. In the main project's base folder, execute:
$ git submodule status
+3557a0e0f7280fb3aba18fb9035d204c7de6344f   lib/ToProgress (0.1.1)
With "git submodule status", we're told which revision each Submodule is checked out at. The little "+" symbol in front of the hash is especially important: it tells us that the Submodule is at a different revision than is officially recorded in the parent repository. This makes sense - since we just changed the checked out revision to the commit tagged "0.1.1".
When performing a simple "git status" in the parent repository, we see that Git regards moving the Submodule's pointer as a change like any other:
$ git status
On branch master
Changes not staged for commit:
    (use "git add ..." to update what will be committed)
    (use "git checkout -- ..." to discard changes in working directory)

    modified:   lib/ToProgress (new commits)

We need to commit this to the repository in order to make it official:
$ git commit -a -m "Moved Submodule pointer to version 1.1.0"

Updating a Submodule When its Pointer was Moved

We just saw how to check out a Submodule at a specific revision. But what if one of our teammates does this in our project? Let's say we integrate his changes (through pull, merge, or rebase for example) after he has moved the Submodule pointer to a different revision:
$ git pull
Updating 43d0c47..3919c52
Fast-forward
 lib/ToProgress | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Git informs us, in a rather shy way, that "lib/ToProgress" was changed. Again, "git submodule status" provides more detailed information:
$ git submodule status
+83298f72c975c29f727c846579c297938492b245 lib/ToProgress (0.1.1-8-g83298f7)
Remember that little "+" sign? It tells us that the Submodule revision was moved - the version we currently have checked out in our project is not the one that is "officially" committed.
The "update" command helps us correct this:
$ git submodule update lib/ToProgress
Submodule path 'lib/ToProgress': checked out '3557a0e0f7280fb3aba18fb9035d204c7de6344f'
NOTE
In most cases, you can use the "git submodule" family of commands without specifying a particular Submodule. By providing a path like in the example above, however, you can address just a certain Submodule.
We now have the same version of the Submodule checked out that our teammate had committed to the repository.
Note that the "update" command also downloads changes for you: imagine that your teammate moved the Submodule's pointer to a revision that you don't have, yet. In that case, Git fetches the corresponding revision in the Submodule and then checks it out for you. Very handy.

Checking for New Changes in the Submodule

Normally, you don't want library code to change very often: you'll want to use a version of the Submodule that you've tested and which you know works flawlessly with your own code.
However, one of the best things about Submodules is that you can easily keep up with new releases (or minor new improvements).
Let's see if there's new code available in the Submodule:
    $ cd lib/ToProgress
    $ git fetch
    remote: Counting objects: 3, done.
    remote: Compressing objects: 100% (3/3), done.
    remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
    Unpacking objects: 100% (3/3), done.
    From https://github.com/djyde/ToProgress
        83298f7..3e20bc2  master     -> origin/master
Note that, to do this, we simply change into the Submodule folder - and can then work like with any normal Git repository (because it is a normal Git repository).
The "git fetch" command, in this case, shows that there are indeed some new changes on the Submodule's remote.
CONCEPT
Before we go ahead and integrate these changes, I'd like to stress an important point once more. When checking the Submodule's status, we're informed that we're on a detached HEAD:
$ git status
    HEAD detached at 3557a0e
    nothing to commit, working directory clean
Normally, in Git, you always have a certain branch checked out. However, you can also choose to check out a specific commit (one that is not the tip of a branch). This is a rather rare case in Git and should normally be avoided.
However, when working with Submodules, it is the normal state to have a certain commit (and not a branch) checked out. You want to make sure you have an exact, static commit checked out in your project - not a branch which, by its nature, moves on with newer commits.


Now, let's integrate the new changes by pulling them into our local Submodule repository. Note that you cannot use the shorthand "git pull" syntax but instead need to specify the remote and branch, too.
This is because of the "detached HEAD" state we're in: since you're not a local branch at the moment, you need to tell Git on which branch you want to integrate the pulled down changes.
$ git pull origin master
If you now were to execute "git status" once more, you'd notice that we're still on that same detached HEAD commit as before - the currently checked out commit was not moved like when we're on a branch. If we want to use the new Submodule code in our main project, we have to explicitly move the HEAD pointer:
$ git checkout master
We're done working in our Submodule; let's move back into our main project:
$ cd ../..
$ git submodule status
+3e20bc25457aa56bdb243c0e5c77549ea0a6a927 lib/ToProgress (0.1.1-9-g3e20bc2)
Since we've just moved the Submodule pointer to a different revision, we need to commit this change to the main repository to make it official.

Working in a Submodule

In some cases, you might want to make some custom changes to a Submodule. You've already seen that working in a Submodule is like working in any other Git repository: any Git commands that you perform inside a Submodule directory are executed in the context of that sub-repository.
Let's say you want to change a tiny bit in a Submodule; you make your changes in the corresponding files, add them to the staging area and commit them.
This might already be the first banana skin: you should make sure you currently have a branch checked out in the Submodule before you commit. That's because if you're in a detached HEAD situation, your commit will easily get lost: it's not attached to any branch and will be gone as soon as you check out anything else.
Apart from that, everything else you've already learned still applies: in the main project, "git submodule status" will tell you that the Submodule pointer was moved and that you'll have to commit the move.
By the way: In case you have uncommitted local changes inside the Submodule, Git will also tell you in the main project:
$ git status
...
    modified:   lib/ToProgress (modified content)
Make sure to always keep a clean state in your Submodules.

Deleting a Submodule

Rather seldomly will you want to remove a Submodule from your project. But if you really want to do this, please don't do this manually: trying to mess with all the configuration files in a correct way will almost inevitably cause problems.
$ git submodule deinit lib/ToProgress
$ git rm lib/ToPogress
$ git status
...
    modified:   .gitmodules
    deleted:    lib/ToProgress
With "git submodule deinit", we made sure that the Submodule is cleanly removed from the configuration files.
With "git rm", we finally delete the actual Submodule files - and other obsolete parts of your configuration.
Commit this and your Submodule will be cleanly removed from the project.

Thursday, 27 December 2018

GIT: How to check my commits in git?

git log --author="Martin"

How to sort my commits in reverse order?

git log --author=Martin --reverse

How to use since option?

git log --author=Martin --reverse --since=2014-05-29

<date> format is: YYYY-MM-DD

GIT: Analyzing the commit history with git log

17.1. Using git log

The git log command shows the history of the Git repository. If no commit reference is specified it starts from the commit referred to by the HEAD pointer.
git log

git log HEAD~10 

git log COMMIT_REF 
shows the history of commits starting from the HEAD~10 commit
shows the history of commits starting from the COMMIT_REF commit

17.2. Helpful parameters for git log

The following gives an overview of useful parameters for the git log command.
git log --oneline  
git log --abbrev-commit 
git log --graph --oneline 
git log --decorate 
--oneline - fits the output of the git log command in one line. --online is a shorthand for "--pretty=oneline --abbrev-commit"
--abbrev-commit - the log command uses shorter versions of the SHA-1 identifier for a commit object but keeps the SHA-1 unique. This parameter uses 7 characters by default, but you can specify other numbers, e.g., --abbrev-commit --abbrev=4.
graph - draws a text-based graphical representation of the branches and the merge history of the Git repository.
decorate - adds symbolic pointers to the log output
17.3. View the change history of a file
To see changes in a file you can use the -p option in the git log command.
git log -- [file_reference] 

git log -p -- [file_reference]  

git log --follow -p -- [file_reference] 
- shows the list of commits for this file
- the -p parameter triggers that the diffs of each commit is shown
--follow allow include renames in the log output

17.4. Configuring output format

You can use the --pretty parameter to configure the output.
# command must be issued in one line, do not enter the line break
git log --pretty=format:'%Cred%h%Creset %d%Creset %s %Cgreen(%cr)
 %C(bold blue)<%an>%Creset' --abbrev-commit
This command creates the output.
Git log pretty output
17.5. Filtering based on the commit message via regular expressions
You can filter the output of the git log command to commits whose commit message, or reflog entry, respectively, matches the specified regular expression pattern with the --grep=<pattern> and --grep-reflog=<pattern> option.
For example the following command instructs the log command to list all commits which contain the word "workspace" in their commit message.
git log --oneline --grep="workspace" 
Greps in commit message for "workspace", oneline parameter included for better readability of the output
There is also the --invert-grep=<pattern> option. When this option is used, git log lists the commits that don’t match the specified pattern.

17.6. Filtering the log output based on author or committer

You can use the --author=<pattern> or --committer=<pattern> to filter the log output by author or committer. You do not need to use the full name, if a substring matches, the commit is included in the log output.
The following command lists all commits with an author name containing the word "Vogel".
git log --author="Vogel"