git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RTC/PATCH] Add 'update-branch' hook

From
Felipe Contreras <felipe.contreras@gmail.com>
Date
Apr 21, 2014, 02:23 UTC
Message-ID
<1398047016-21643-1-git-send-email-felipe.contreras@gmail.com>

This hook is invoked whenever a branch is updated, either when a branch is created or updated with 'git branch', or when it's rebased with 'git rebase'. It receives two parameters; the name of the branch, and the SHA-1 of the latest commit, additionally, if there was a base commit the branch was rebased onto, a third parameter contains it.

It can be used to verify the validity of branch names, and also to keep track of the origin point of a branch, which is otherwise not possible to find out [1].

[1] http://thread.gmane.org/gmane.comp.version-control.git/198587
Signed-off-by: Felipe Contreras <felipe.contreras@gmail.com>
---
 Documentation/githooks.txt    |  9 +++++++++
 branch.c                      |  6 ++++++
 builtin/clone.c               |  7 +++++--
 git-rebase--interactive.sh    |  6 +++++-
 git-rebase.sh                 |  6 +++++-
 t/t5408-update-branch-hook.sh | 39 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 69 insertions(+), 4 deletions(-)
 create mode 100755 t/t5408-update-branch-hook.sh
diff --git a/Documentation/githooks.txt b/Documentation/githooks.txt
index d954bf6..9e50697 100644
--- a/Documentation/githooks.txt
+++ b/Documentation/githooks.txt
@@ -381,6 +381,15 @@ rebase::
 The commits are guaranteed to be listed in the order that they were
 processed by rebase.
 
+update-branch
+~~~~~~~~~~~~~
+
+This hook is invoked whenever a branch is updated, either when a branch is
+created or updated with 'git branch', or when it's rebased with 'git rebase'.
+It receives two parameters; the name of the branch, and the SHA-1 of the latest
+commit, additionally, if there was a base commit the branch was rebased onto, a
+third parameter contains it.
+
 
 GIT
 ---
diff --git a/branch.c b/branch.c
index 660097b..c2058d1 100644
--- a/branch.c
+++ b/branch.c
@@ -4,6 +4,7 @@
 #include "refs.h"
 #include "remote.h"
 #include "commit.h"
+#include "run-command.h"
 
 struct tracking {
 	struct refspec spec;
@@ -304,6 +305,11 @@ void create_branch(const char *head,
 	if (real_ref && track)
 		setup_tracking(ref.buf + 11, real_ref, track, quiet);
 
+	if (run_hook_le(NULL, "update-branch", ref.buf + 11, sha1_to_hex(sha1), NULL)) {
+		unlock_ref(lock);
+		die("hook 'update-branch' returned error");
+	}
+
 	if (!dont_change_ref)
 		if (write_ref_sha1(lock, sha1, msg) < 0)
 			die_errno(_("Failed to write ref"));
diff --git a/builtin/clone.c b/builtin/clone.c
index 9b3c04d..6ec96e5 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -581,9 +581,10 @@ static void update_remote_refs(const struct ref *refs,
 	}
 }
 
-static void update_head(const struct ref *our, const struct ref *remote,
+static int update_head(const struct ref *our, const struct ref *remote,
 			const char *msg)
 {
+	int err = 0;
 	if (our && starts_with(our->name, "refs/heads/")) {
 		/* Local default branch link */
 		create_symref("HEAD", our->name, NULL);
@@ -591,6 +592,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
 			const char *head = skip_prefix(our->name, "refs/heads/");
 			update_ref(msg, "HEAD", our->old_sha1, NULL, 0, DIE_ON_ERR);
 			install_branch_config(0, head, option_origin, our->name);
+			err = run_hook_le(NULL, "update-branch", head, sha1_to_hex(our->old_sha1), NULL);
 		}
 	} else if (our) {
 		struct commit *c = lookup_commit_reference(our->old_sha1);
@@ -606,6 +608,7 @@ static void update_head(const struct ref *our, const struct ref *remote,
 		update_ref(msg, "HEAD", remote->old_sha1,
 			   NULL, REF_NODEREF, DIE_ON_ERR);
 	}
+	return err;
 }
 
 static int checkout(void)
@@ -987,7 +990,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	update_remote_refs(refs, mapped_refs, remote_head_points_at,
 			   branch_top.buf, reflog_msg.buf, transport, !is_local);
 
-	update_head(our_head_points_at, remote_head, reflog_msg.buf);
+	err = update_head(our_head_points_at, remote_head, reflog_msg.buf);
 
 	transport_unlock_pack(transport);
 	transport_disconnect(transport);
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 1c41cbd..084dc36 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -631,7 +631,11 @@ do_next () {
 		git update-ref -m "$message" $head_name $newhead $orig_head &&
 		git symbolic-ref \
 		  -m "$GIT_REFLOG_ACTION: returning to $head_name" \
-		  HEAD $head_name
+		  HEAD $head_name &&
+		if test -x "$GIT_DIR"/hooks/update-branch; then
+			"$GIT_DIR"/hooks/update-branch $branch_name \
+				$newhead $onto
+		fi
 		;;
 	esac && {
 		test ! -f "$state_dir"/verbose ||
diff --git a/git-rebase.sh b/git-rebase.sh
index 2c75e9f..ededa32 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -149,7 +149,11 @@ move_to_original_branch () {
 			$head_name $(git rev-parse HEAD) $orig_head &&
 		git symbolic-ref \
 			-m "rebase finished: returning to $head_name" \
-			HEAD $head_name ||
+			HEAD $head_name &&
+		if test -x "$GIT_DIR"/hooks/update-branch; then
+			"$GIT_DIR"/hooks/update-branch $branch_name \
+				$(git rev-parse HEAD) $onto
+		fi ||
 		die "$(gettext "Could not move back to $head_name")"
 		;;
 	esac
diff --git a/t/t5408-update-branch-hook.sh b/t/t5408-update-branch-hook.sh
new file mode 100755
index 0000000..d921c0e
--- /dev/null
+++ b/t/t5408-update-branch-hook.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+test_description='Test the update-branch hook'
+
+. ./test-lib.sh
+
+setup () {
+	mkdir -p .git/hooks &&
+	cat > .git/hooks/update-branch <<-'EOF' &&
+	#!/bin/sh
+	echo $@ > .git/update-branch.args
+	EOF
+	chmod +x .git/hooks/update-branch &&
+	echo one > content &&
+	git add content &&
+	git commit -a -m one
+}
+
+setup
+
+test_expect_success 'creating a branch' '
+	git checkout -b test master &&
+	echo two > new &&
+	git add new &&
+	git commit -a -m two
+	echo "test $(git rev-parse master)" > expected &&
+	test_cmp expected .git/update-branch.args
+'
+
+test_expect_success 'doing a rebase' '
+	git checkout -b next master &&
+	echo three > content &&
+	git commit -a -m three &&
+	git rebase --onto next master test &&
+	echo "test $(git rev-parse HEAD) $(git rev-parse next)" > expected &&
+	test_cmp expected .git/update-branch.args
+'
+
+test_done
-- 
1.9.2+fc1.1.g5c924db
Next: Eric Sunshine
Message 1 of 39 in “Add 'update-branch' hook”
  1. Add 'update-branch' hookFelipe Contreras, Apr 21, 2014
  2. Eric SunshineApr 21, 2014
  3. Ilya BobyrApr 21, 2014
  4. Felipe ContrerasApr 21, 2014
  5. Ilya BobyrApr 21, 2014
  6. Felipe ContrerasApr 21, 2014
  7. Ilya BobyrApr 21, 2014
  8. Felipe ContrerasApr 21, 2014
  9. Stephen LeakeApr 22, 2014
  10. Felipe ContrerasApr 22, 2014
  11. Ilya BobyrApr 22, 2014
  12. Felipe ContrerasApr 22, 2014
  13. Stephen LeakeApr 23, 2014
  14. Felipe ContrerasApr 23, 2014
  15. Junio C HamanoApr 23, 2014
  16. Felipe ContrerasApr 24, 2014
  17. Junio C HamanoApr 26, 2014
  18. Felipe ContrerasApr 26, 2014
  19. Stephen LeakeApr 24, 2014
  20. Felipe ContrerasApr 24, 2014
  21. Junio C HamanoApr 21, 2014
  22. Felipe ContrerasApr 21, 2014
  23. Junio C HamanoApr 21, 2014
  24. Felipe ContrerasApr 23, 2014
  25. Junio C HamanoApr 23, 2014
  26. Felipe ContrerasApr 24, 2014
  27. Ilya BobyrApr 22, 2014
  28. Felipe ContrerasApr 22, 2014
  29. Ilya BobyrApr 21, 2014
  30. Felipe ContrerasApr 21, 2014
  31. Ilya BobyrApr 21, 2014
  32. Felipe ContrerasApr 21, 2014
  33. Ilya BobyrApr 22, 2014
  34. Felipe ContrerasApr 22, 2014
  35. Felipe ContrerasApr 21, 2014
  36. Ilya BobyrApr 22, 2014
  37. Felipe ContrerasApr 22, 2014
  38. Ilya BobyrApr 22, 2014
  39. Felipe ContrerasApr 22, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.