Git and Visual Studio 2017 part 12 : Compare your items in Git
In previous article, I explained how to check and change git configuration. In this article, I play with “diff” command in Git to compare items. I will write how to compare items in VS in the next article.
Compare items in Git
Git provides “diff” command to compare items. it compares items between two commits, items in a commit and staging area, or items in staging area and working directory, items between branches, etc. I can compare many variations such as entire items in a commit, items under a directory or just a single file. Let’s see how it actually works.
Compare two commits
1. Run ‘git log --oneline --graph --all’ and ‘git status’ to see current situation.
2. Run ‘git diff HEAD~1 HEAD', which compares the latest commit (fe853ab) and previous commit (b54daa4). The result shows changes from HEAD~1 to HEAD but this is a bit difficult to read. The first line shows which file is compared. In this case, README.md. The second line shows which contents are compared. In this case, blob fb90057 and edf7878. 100644 means normal file. The 3rd and 4th line indicates “-“ means “a” which is HEAD~1 and “+” means “b” which is HEAD. The line start with @@ means git shows 2 lines from 1st line for file a, and three lines from 1st line for file b. Why? because it starts with “-“ or “+” which means “a” or “b”, then which line to start (in this case, 1st line for both files), followed by how many line. The rest of the results are actual content diff results.
3. Run ‘git cat-file blob fb90057’ and ‘git cat-file blob edf7878’ to see actual contents.
4. You may wonder what is HEAD~1, as HEAD has two parents as a result of merge. Run ‘git cat-file commit HEAD’ to see current HEAD info. I see first parent SHA1 hash is b54daa4, therefore HEAD~1 is commit b54daa4.
5. There are several ways to determine this. Run ‘git rev-parse HEAD~1’ which shows SHA1 hash value for HEAD~1. This is useful command to confirm actual SHA1 hash for HEAD, HEAD~n, branches or tags.
6. Another way is to run ‘git log --oneline --first-parent’ which shows tree for first parent only.
7. If you want to compare HEAD with another parent, then simply specify the SHA1 hash. Now it shows difference for multiple files.
8. If I need less information, then run ‘git diff --raw 28fd556 HEAD’ or ‘git diff --stat 28fd556 HEAD’.
Compare specific items
If you want to compare specific files only, then add path at the end of diff command.
1. Run ‘git diff 28fd556 HEAD README.md’, then git only shows diff for README.md
2. Run ‘git diff HEAD~5 HEAD VS_Git’, then git only shows files diff in VS_Git folder since last 5 commits.
Compare items between working directory, staged area and commit
What if I need to compare items between working directory and staged area or even a commit?
1. Run ‘echo “Added in staged” >> README.md’ and ‘git add README.md’.
2. Run ‘echo “Added in working directly only” >> README.md’ and ‘git status’. Now I have different version of README.md in commits, staged area and working directory.
3. Run ‘git diff’. Obviously, this compares README.md file in staged area and working directory.
4. Run ‘git diff --cached’. This compares README.md file in the latest commit and staging area.
5. Run ‘git diff HEAD’. This compares the latest commit and working directory.
6. Let’s see actual content by using SHA1 hash. Run ‘git cat-file blob edf7878’, which is README.md file in the latest commit.
7. How about 8554cf6? Run ‘git cat-file blog 8554cf6’, but git cannot find the file. Why?
8. This is because git will create object when we issue ‘git add’ command. Therefore items in working directly don’t exist as git object. Then where SHA1 hash 8554cf6 came from? Run ‘git hash-object README.md’ gives you the answer. This command hashes the item and gives you the SHA1 hash value. If I run ‘git add README.md’ right now, git will add folder named ‘85’ in .git\objects folder and add file as ‘54cf641f08f667335b080656b32d0518b3c929’ its name.
Compare items in branches is same as compare items in commits, as branch is just a pointer to a commit.
1. Run ‘git checkout -b dev’ to create new branch “dev” and checkout. Staging area and working directory items are now in dev branch.
2. Run ‘git commit -m “Add staged comment in README.md”’, which only commit currently staged changes.
3. Run ‘git diff dev master’. It shows difference in dev branch to master branch. As dev branch has “Added in staged” line for README.md, when compared with master, it is shows as deleted line.
4. Run ‘git diff dev…master'. This has different meaning from above. It check all the changes happened in master, after dev branch is created. In this case, nothing happened.
5. Run ‘git checkout -f master’ to switch branch, ‘type README.md’ to see content of the file, ‘echo “Added in master” >> README.md’ to add new line, and ‘git commit -am “Added line in README.md in master”’ to add new commit. I used -f option when checkout as there was local change to README.md which checkout will override.
6. Now, run ‘git diff dev master’ and ‘git diff dev…master’. I can clearly see the change.
Reset for next article
As I want to do the same for next article, run following commands to reset then all.
‘git checkout master’
‘git branch -D dev’
‘git reset --hard fe853ab’
Comparing items are very important especially when something went wrong. I usually use Visual Studio to compare items, but it is good to know what we can do via git command anyway. Go to next article.