📜 ⬆️ ⬇️

Using Git hooks to block edits of published commits

Hi, Habr!

Those who work with Git are familiar with the way to edit the last commit with the git commit --amend . This is convenient for minor edits (change the comment to the commit, correct the line in the code, etc.), because quite often good thoughts about the commit come to mind after this commit has been made.

But with this method of editing commits, you should be careful when you work with a remote repository and even more carefully when you work on source code as part of a command. The safe use of the --amend option ends where the use of the git push command begins.

When you commit with the --amend option, a new commit is created (with a new hash), which replaces the previous one, and that previous commit is removed from the history.
')
If you edit your already published commit (sent to a remote repository with git push ), then in the future you will create problems for yourself (when you try to publish your edited commit) and ( most important! ) Create problems for other developers who managed to get your local repositories old commit In this case, both you and other developers are given the headache of clearing the commit history to correct the situation.

Most recommendations come down to advice: DON'T RULE PUBLISHED COMMITTES!

And everything would be great if the git commit --amend not so good and comfortable! She wants to use, not looking at the history of commits in the remote repository. Therefore, I had a desire to automate such checks.

For such automation in the Git system, interceptors (hooks) will serve perfectly, namely those that work on the client side. They are stored in the service directory .git/hooks and are script files with predefined names corresponding to their functional purpose. For my task, a message sniffer is suitable for the prepare-commit-msg commit .

The essence of the idea is:
  1. We intercept the git commit --amend ;
  2. Get the value of the last commit hash in the local branch;
  3. Get the value of the last commit hash in the remote branch;
  4. We compare them, and if they are equal, then we display a warning and comment on the content part of the commit message — so that when you exit editing, the commit is canceled due to an empty message (“Aborting commit due to empty commit message”).

Prepare-commit-msg

 #!/bin/bash case "$2,$3" in commit,HEAD) #  short SHA-1      sha1_local=$(git branch -vv | \ perl -lne 'print "$1" if /\*{1}\s+\S+\s+(\w+)\s+\[(\S+)\/(\S+).*\]\s+.*/') #     (remote branch) remote_branch=$(git branch -vv | \ perl -lne 'print "$1/$2" if /\*{1}\s+\S+\s+\w+\s+\[(\S+)\/(\S+).*\]\s+.*/') #  short SHA-1      (remote branch) sha1_remote=$(git branch -rv | \ awk -v branch=$remote_branch '{ if ($1 == branch) print $2 }') if [ -n "$sha1_local" ] && [ -n "$sha1_remote" ] && [ "$sha1_local" = "$sha1_remote" ] then #   ,      #    -   ci_comment=$(cat "$1" | grep -v '#' | perl -lne 'print "# $_"') ci_autogen=$(cat "$1" | grep '#') echo -e "$ci_comment" > "$1" #    echo -e "# !      !\n" >> "$1" echo -e "$ci_autogen" >> "$1" fi ;; *) ;; esac 

An example of the work of this hook is shown below:



As you can see, the user still has the opportunity if he wants to make a commit - for this he should uncomment the commit message. If there is a task of more rigidly suppressing attempts to edit published commits, then Git has a pre-commit interceptor, which runs before the creation of a commit message.

Source: https://habr.com/ru/post/221819/


All Articles