Verify that a file was only modified at the end between 2 commits

Viewed 63

I have a file in my repository and I only want to allow inserts at the end.

What linux command can I use to validate that between two git commits the file was only modified at the end?

2 Answers

There is no Git command that does this, but you can script it in Bash (or your shell of choice):

You can create a script that does this:

#!/bin/bash

# Create a file which is a version of your file of interest before last commit

git --no-pager show HEAD~:<file> > original

# Get the number of lines for that file and call it n:

n=$(cat original | wc -l)

# Test whether the last commit modified the file other than
# by adding content at the end

[[ "$(diff <(cat original) <(head -$n <file>))" == "" ]]

# Finally, clean up by deleting the temp file:

rm original

This will return 0 if the file was modified only at the end (or not at all) and 1 if there was a modification that you want to block (i.e. not at the end).

Of course, you need to replace <file> with the path of your file of interest.

If the 2 commits you are interested in are not the last 2 commits, you can modify the script to be more general. Here, for instance, I will use <hash1> and <hash2> for the 2 commits, but you can use any reference that is convenient to identify any 2 commits:

#!/bin/bash

# Create a file which is a version of your file of interest at the first commit
# you care about (using its hash):

git --no-pager show <hash1>:<file> > original

# Create a file which is a version of your file of interest at the second commit
# you care about (using its hash):

git --no-pager show <hash2>:<file> > next

# Get the number of lines for the first of these files and call it n:

n=$(cat original | wc -l)

# Test whether the commit with hash2 modified the file other
# than by adding content at the end

[[ "$(diff <(cat original) <(head -$n next))" == "" ]]

# Finally, clean up by deleting the 2 temp files:

rm original next

Alternatively, for convenience since you will probably need to test this often in your pipeline, you can create a function and add it to your .bashrc or equivalent:

function check {
    local n
    git --no-pager show "$2":"$1" > original
    git --no-pager show "$3":"$1" > next
    n=$(cat original | wc -l)
    [[ "$(diff <(cat original) <(head -$n next))" == "" ]]
    rm original next
}

You can then use it with:

check <file-path> <commit-hash1> <commit-hash2>

You can use git log hash1..hash2 to see if one file modified with --stat and the modification content with -c.

Note, here the hash2 should be the older commit, and hash2 is the recent commit.Otherwise you'll get nothing

$ git log --stat bdf402d1a387ba9a8..620f05b4c9 library/HQ/groupsql.sql
commit 620f05b4c9ce53549b4ad8003de433e44054dea6
Author: lu <lu.com>
Date:   Fri Oct 9 17:57:24 2020 +0800

    specify material,price when create class course

 library/HQ/groupsql.sql | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

commit ed0c5461c79acd43072ca1d2655cec76076d7de3
Author: lu <lu.com>
Date:   Mon Sep 28 20:56:23 2020 +0800

    remove material history

 library/HQ/groupsql.sql | 14 --------------
 1 file changed, 14 deletions(-)
Related