3

I am trying to get the git diff between 2 strings. The following command works:

git diff $(echo "my first string" | git hash-object -w --stdin) $(echo "my second string" | git hash-object -w --stdin)  --word-diff

However, it fails if not executed inside a Git directory.

I believe this portion of the command is failing:

echo "my first string" | git hash-object -w --stdin

Is there any way around this so that it can be executed outside a Git directory?

2
  • 1
    This seems to address your problem: stackoverflow.com/questions/7149984/… Commented Sep 4, 2017 at 11:20
  • thanks for the heads up ... if my code is executed on countless other machines, is there a way to reliablly set --git-dir ? Commented Sep 4, 2017 at 11:26

2 Answers 2

4

I believe this portion of the command is failing:

echo "my first string" | git hash-object -w --stdin

Is there any way around this so that it can be executed outside a git directory?

The problem you are having is because of the -w option that you pass to the git hash-object command. That option requires an existing repository as it has a side effect of writing the object into the git database.

Proof:

$ echo "my first string" | git hash-object -w --stdin
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

$ echo "my first string" | git hash-object --stdin
3616fdee3ac48e5db02fbf9d5e1c2941cfa3e165

However, since your final goal is to obtain the git diff between two given strings you have to have a git repository if you want to do it with the help of git hash-object1. To this end you can generate a temporary empty repository:

$ tmpgitrepo="$(mktemp -d)"

$ git init "$tmpgitrepo"
Initialized empty Git repository in /tmp/tmp.MqBqDI1ytM/.git/

$ (export GIT_DIR="$tmpgitrepo"/.git; git diff $(echo "my first string" | git hash-object -w --stdin) $(echo "my second string" | git hash-object -w --stdin)  --word-diff)
diff --git a/3616fdee3ac48e5db02fbf9d5e1c2941cfa3e165 b/2ab8560d75d92363c8cb128fb70b615129c63371
index 3616fde..2ab8560 100644
--- a/3616fdee3ac48e5db02fbf9d5e1c2941cfa3e165
+++ b/2ab8560d75d92363c8cb128fb70b615129c63371
@@ -1 +1 @@
my [-first-]{+second+} string

$ rm -rf "$tmpgitrepo"

This approach can be packaged into a bash function:

git-diff-strings()
(
    local tmpgitrepo="$(mktemp -d)"
    trap "rm -rf $tmpgitrepo" EXIT
    git init "$tmpgitrepo" &> /dev/null
    export GIT_DIR="$tmpgitrepo"/.git
    local s1="$1"
    local s2="$2"
    shift 2
    git diff $(git hash-object -w --stdin <<< "$s1") $(git hash-object -w --stdin <<< "$s2") "$@"
)

Usage:

git-diff-strings <string1> <string2> [git-diff-options]

Example:

git-diff-strings "first string" "second string" --word-diff

1 Note that you can git diff two strings by creating 2 temporary files containing those strings, in which case you don't need a git repository.

Sign up to request clarification or add additional context in comments.

1 Comment

Excellent stuff, thanks Leon, adding all this functionality to my app now - much appreciated :D
1

@danday74 I am unable to write a comment based on your feedback (due to permissions on StackOverflow) so here is my answer. You can set the environment variable using GIT_DIR. If you do this on the multiple machines (you would need to be able to set this variable on such machines), then you will be able to reliably set --git-dir.

Hope this helps.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.