我在登录时运行一个脚本,打开一个终端并在其中运行一个读取
的shell脚本git pull --rebase && git log
但是,即使上游没有变化,这个git日志也会运行。如果有更改,我该如何修改此脚本才能运行git log
?
答案 0 :(得分:5)
你可以这样做:
prev=$(git rev-list HEAD -n 1)
git pull --rebase
test $prev = $(git rev-list HEAD -n 1) || git log
答案 1 :(得分:2)
“常规”(无--rebase
)git pull
确实运行git fetch
,后跟git merge
。 git pull --rebase
真正运行git fetch
后跟git rebase
(如果您正在重新定位的“跟踪分支”本身已经重新设置,则会有一些聪明。)
在这两种情况下,实际上是fetch
步骤带来了上游变化。第二部分(合并或重组)只是将这些上游更改(如果有)与您的更改(如果有)组合在一起。所以你想知道的是:从上游跟踪分支获取的是什么?
janos' answer可以正常使用。但是,要了解为什么,请考虑提交图在git pull --rebase
之前和之后的显示方式。我们将从一个简单的图表开始,只需提交A
,B
和Y
,其中A
和B
位于上游分支的“上方” Y
是您自己的提交,将被重新定位:
A - B <-- origin/master
\
Y <-- HEAD=master
(这假设您在分支master
上并且您的遥控器名为origin
,但由于我们只查看HEAD
它适用于任何分支和任何远程。)< / p>
如果fetch
步骤不执行任何操作,则此图表在(无操作/跳过)合并或重组步骤后保持不变。因此HEAD
仍为master
仍然引用提交Y
(Y
代表43be6d8...
之类的长SHA-1字符串之一;这些是“真实的名字“提交,他们永远不会改变;你不能改变提交,你只能停止看它,我们将在下面看到。”
如果fetch
步骤引入了新的提交C
,则中间图如下所示:
A - B - C <-- origin/master
\
Y <-- HEAD=master
现在git pull --rebase
必须运行git rebase
才能将您的Y
提交到新提交。现有的Y
提交仍然存在,但标签master
被移动以指向新提交。让我们调用新提交Y'
,因为它的内容与Y
的内容基本相同,只是父ID现在是C
而不是B
。所以现在你有了:
A - B - C <-- origin/master
. \
. Y' <-- HEAD=master
.
Y [no label - abandoned]
所以,让我们采用那个简短的脚本并稍微简化一下(我将反转测试,即使这会使它更长一些,并添加双引号):
prev=$(git rev-parse HEAD)
git pull --rebase
test "$prev" != "$(git rev-parse HEAD)" && git log
第一个rev-parse
找到HEAD
提交(Y
)的SHA-1。然后我们执行git pull --rebase
,它会引入或不引入新的提交。最后,我们看到HEAD
是否指向新的不同提交(Y'
)。如果是这样,旧的SHA-1和新的SHA-1会有所不同,!=
测试会成功,我们将运行git log
。
值得考虑一些边缘和错误情况:
如果没有提交Y
,即你的分支和上游分支同步怎么办?
没问题!这里HEAD
会在B
之前找到提交pull
,并再次找到提交B
(无更改)或提交C
(某些更改)。测试仍然会做正确的事。
如果pull --rebase
因为无法到达上游而失败怎么办?
这导致了与上游没有变化相同的行为。
如果pull --rebase
能够获取但是rebase失败怎么办?
在这种情况下,您的提交(Y
)仍然是您的HEAD
提交。这里的脚本认为没有任何改变并跳过git log
...但是git pull --rebase
步骤打印了一些关于失败的rebase的错误,所以这可能是正确的。
如果没有HEAD
版本怎么办? (空仓库;不在git仓库中;其他奇怪的错误。)
在这种情况下,git rev-parse
将退出并显示错误,prev
将设置为空字符串。 git pull --rebase
步骤也将失败,第二个git rev-parse
将再次失败。这就是我添加双引号的原因:现在我们将运行test "" != ""
。这两个空字符串相等,脚本将跳过git log
步骤。所以你会得到一些额外的错误信息,但它仍然会有效。
(为了使这个更加健壮,如果第一个git rev-parse HEAD
失败,我们可能应该停止整个过程,但这相对较小。)
这里更复杂(更有趣)的方法是找到实际的上游分支,看看在fetch
步骤中发生了什么。这将允许您记录上游分支上执行的操作(如果有的话)。事实证明,使用@{u}
gitrevisions语法很容易:
old=$(git rev-parse @{u}) || exit # find current upstream, bail on error
git pull --rebase || exit # update, bail on error
new=$(git rev-parse @{u}) || exit # find new upstream, bail on error
[ $old = $new ] && exit # nothing to do if unchanged
ours=$(git rev-parse HEAD) || exit
if [ ! -z "$(git rev-list $new..$old)" ]; then
# this is pretty rare; pull --rebase knows what to do though
# could add "we rebased onto new head" if $ours != $new, perhaps
echo "upstream removed old commits:"
git log --oneline $new..$old
fi
if [ $ours != $new ]; then
echo "upstream added new commits, which we rebased onto:"
else
echo "upstream added new commits:"
fi
git log $old..$new
(注意:上面的脚本完全未经测试)。