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

[RFE/PATCH] git-fetch-rebase

From
JFJosé Fonseca <jrfonseca@tungstengraphics.com>
Date
Dec 14, 2007, 22:12 UTC
Message-ID
<1197670351.21175.33.camel@localhost>
Hi,

For those who use git as a better centralized SCM, it became a common practice to do git-fetch + git-rebase instead of just git-pull, so that the history is linear, instead of being full of tiny merges.

However, there is no git command for such common procedure (at least AFAIK). Attached is a variation of the git-pull porcelain (taken from git version debian.1.5.3.7.1-dirty) that instead of doing git-fetch + git-merge, it does git-fetch + git-rebase.

I've been using this git-fetch-rebase script frequently, and it really boosts my productivity (I use it when updating from the main repository, and before pushing my changes to the main repository).

I'd like see this script, or an equivalent command, included the git distribution.

Cheers,
José Fonseca

#!/bin/sh # # Copyright (c) 2007 José Fonseca # Copyright (c) 2005 Junio C Hamano # # Fetch a remote ref and rebase the current HEAD on top of it.

USAGE='[-s strategy]... [<fetch-options>] <repo> <head>' LONG_USAGE='Fetch a remote ref and rebase the current HEAD onto it.' SUBDIRECTORY_OK=Yes . git-sh-setup set_reflog_action "fetch-rebase $*" require_work_tree cd_to_toplevel

test -z "$(git ls-files -u)" ||
	die "You are in the middle of a conflicted merge."
strategy_args=
while :
do
	case "$1" in
	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
		--strateg=*|--strategy=*|\
	-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
		case "$#,$1" in
		*,*=*)
			strategy=`expr "z$1" : 'z-[^=]*=\(.*\)'` ;;
		1,*)
			usage ;;
		*)
			strategy="$2"
			shift ;;
		esac
		strategy_args="${strategy_args}-s $strategy "
		;;
	-h|--h|--he|--hel|--help)
		usage
		;;
	*)
		# Pass thru anything that may be meant for fetch.
		break
		;;
	esac
	shift
done

orig_head=$(git rev-parse --verify HEAD 2>/dev/null) git-fetch "$@" || exit 1

merge_head=$(sed -e '/	not-for-merge	/d' \
	-e 's/	.*//' "$GIT_DIR"/FETCH_HEAD | \
	tr '\012' ' ')
case "$merge_head" in
'')
	curr_branch=$(git symbolic-ref -q HEAD)
	case $? in
	  0) ;;
	  1) echo >&2 "You are not currently on a branch; you must explicitly"
	     echo >&2 "specify which branch you wish to rebase onto:"
	     echo >&2 "  git fetch-rebase <remote> <branch>"
	     exit 1;;
	  *) exit $?;;
	esac
	curr_branch=${curr_branch#refs/heads/}
	echo >&2 "You asked me to rebase without telling me which branch you"
	echo >&2 "want to rebase, and 'branch.${curr_branch}.merge' in"
	echo >&2 "your configuration file does not tell me either.  Please"
	echo >&2 "name which branch you want to rebase on the command line and"
	echo >&2 "try again (e.g. 'git fetch-rebase <repository> <refspec>')."
	echo >&2 "See git-pull(1) for details on the refspec."
	echo >&2
	echo >&2 "If you often rebase to the same branch, you may want to"
	echo >&2 "configure the following variables in your configuration"
	echo >&2 "file:"
	echo >&2
	echo >&2 "    branch.${curr_branch}.remote = <nickname>"
	echo >&2 "    branch.${curr_branch}.merge = <remote-ref>"
	echo >&2 "    remote.<nickname>.url = <url>"
	echo >&2 "    remote.<nickname>.fetch = <refspec>"
	echo >&2
	echo >&2 "See git-config(1) for details."
	exit 1
	;;
?*' '?*)
	echo >&2 "Cannot rebase onto multiple branches"
	exit 1
	;;
esac
if test -z "$orig_head"
then
	echo >&2 "Cannot rebase empty head"
	exit 1
fi
exec git-rebase $strategy_args $merge_head

--- /usr/bin/git-pull 2007-12-04 09:46:21.000000000 +0000 +++ git-fetch-rebase 2007-12-13 12:38:52.000000000 +0000

@@ -1,34 +1,25 @@
 #!/bin/sh
 #
+# Copyright (c) 2007 José Fonseca
 # Copyright (c) 2005 Junio C Hamano
 #
-# Fetch one or more remote refs and merge it/them into the current HEAD.
+# Fetch a remote ref and rebase the current HEAD on top of it.
 
-USAGE='[-n | --no-summary] [--no-commit] [-s strategy]... [<fetch-options>] <repo> <head>...'
-LONG_USAGE='Fetch one or more remote refs and merge it/them into the current HEAD.'
+USAGE='[-s strategy]... [<fetch-options>] <repo> <head>'
+LONG_USAGE='Fetch a remote ref and rebase the current HEAD onto it.'
 SUBDIRECTORY_OK=Yes
 . git-sh-setup
-set_reflog_action "pull $*"
+set_reflog_action "fetch-rebase $*"
 require_work_tree
 cd_to_toplevel
 
 test -z "$(git ls-files -u)" ||
 	die "You are in the middle of a conflicted merge."
 
-strategy_args= no_summary= no_commit= squash=
+strategy_args=
 while :
 do
 	case "$1" in
-	-n|--n|--no|--no-|--no-s|--no-su|--no-sum|--no-summ|\
-		--no-summa|--no-summar|--no-summary)
-		no_summary=-n ;;
-	--summary)
-		no_summary=$1
-		;;
-	--no-c|--no-co|--no-com|--no-comm|--no-commi|--no-commit)
-		no_commit=--no-commit ;;
-	--sq|--squ|--squa|--squas|--squash)
-		squash=--squash ;;
 	-s=*|--s=*|--st=*|--str=*|--stra=*|--strat=*|--strate=*|\
 		--strateg=*|--strategy=*|\
 	-s|--s|--st|--str|--stra|--strat|--strate|--strateg|--strategy)
@@ -55,30 +46,7 @@
 done
 
 orig_head=$(git rev-parse --verify HEAD 2>/dev/null)
-git-fetch --update-head-ok "$@" || exit 1
-
-curr_head=$(git rev-parse --verify HEAD 2>/dev/null)
-if test "$curr_head" != "$orig_head"
-then
-	# The fetch involved updating the current branch.
-
-	# The working tree and the index file is still based on the
-	# $orig_head commit, but we are merging into $curr_head.
-	# First update the working tree to match $curr_head.
-
-	echo >&2 "Warning: fetch updated the current branch head."
-	echo >&2 "Warning: fast forwarding your working tree from"
-	echo >&2 "Warning: commit $orig_head."
-	git update-index --refresh 2>/dev/null
-	git read-tree -u -m "$orig_head" "$curr_head" ||
-		die 'Cannot fast-forward your working tree.
-After making sure that you saved anything precious from
-$ git diff '$orig_head'
-output, run
-$ git reset --hard
-to recover.'
-
-fi
+git-fetch "$@" || exit 1
 
 merge_head=$(sed -e '/	not-for-merge	/d' \
 	-e 's/	.*//' "$GIT_DIR"/FETCH_HEAD | \
@@ -90,21 +58,21 @@
 	case $? in
 	  0) ;;
 	  1) echo >&2 "You are not currently on a branch; you must explicitly"
-	     echo >&2 "specify which branch you wish to merge:"
-	     echo >&2 "  git pull <remote> <branch>"
+	     echo >&2 "specify which branch you wish to rebase onto:"
+	     echo >&2 "  git fetch-rebase <remote> <branch>"
 	     exit 1;;
 	  *) exit $?;;
 	esac
 	curr_branch=${curr_branch#refs/heads/}
 
-	echo >&2 "You asked me to pull without telling me which branch you"
-	echo >&2 "want to merge with, and 'branch.${curr_branch}.merge' in"
+	echo >&2 "You asked me to rebase without telling me which branch you"
+	echo >&2 "want to rebase, and 'branch.${curr_branch}.merge' in"
 	echo >&2 "your configuration file does not tell me either.  Please"
-	echo >&2 "name which branch you want to merge on the command line and"
-	echo >&2 "try again (e.g. 'git pull <repository> <refspec>')."
+	echo >&2 "name which branch you want to rebase on the command line and"
+	echo >&2 "try again (e.g. 'git fetch-rebase <repository> <refspec>')."
 	echo >&2 "See git-pull(1) for details on the refspec."
 	echo >&2
-	echo >&2 "If you often merge with the same branch, you may want to"
+	echo >&2 "If you often rebase to the same branch, you may want to"
 	echo >&2 "configure the following variables in your configuration"
 	echo >&2 "file:"
 	echo >&2
@@ -117,21 +85,15 @@
 	exit 1
 	;;
 ?*' '?*)
-	if test -z "$orig_head"
-	then
-		echo >&2 "Cannot merge multiple branches into empty head"
-		exit 1
-	fi
+	echo >&2 "Cannot rebase onto multiple branches"
+	exit 1
 	;;
 esac
 
 if test -z "$orig_head"
 then
-	git update-ref -m "initial pull" HEAD $merge_head "" &&
-	git read-tree --reset -u HEAD || exit 1
-	exit
+	echo >&2 "Cannot rebase empty head"
+	exit 1
 fi
 
-merge_name=$(git fmt-merge-msg <"$GIT_DIR/FETCH_HEAD") || exit
-exec git-merge $no_summary $no_commit $squash $strategy_args \
-	"$merge_name" HEAD $merge_head
+exec git-rebase $strategy_args $merge_head
Next: Junio C Hamano
Message 1 of 3 in “git-fetch-rebase”
  1. git-fetch-rebaseJosé Fonseca, Dec 14, 2007
  2. Junio C HamanoDec 14, 2007
  3. José FonsecaDec 15, 2007

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.