我的工作流程的一部分涉及做很多这样的事情:
我正在尝试编写一个脚本来同时执行所有这些操作,所以我可以从终端调用它.
#!/bin/bash
# First stash our local changes
git stash
# Then git pull to update our repo
git pull
# Pop the stash
git stash pop
# Launch mergetool if necessary
git mergetool
Run Code Online (Sandbox Code Playgroud)
我遇到的问题是,如果我意外地运行,并且没有对藏匿的更改,则git stash pop应用一些(通常超级旧的)存储.我想要做的git stash pop只是在我之前实际存在的东西之前运行.有没有办法做到这一点?
正如XavierÁlvarez 所说,codeWizard写道,git stash完全避免这里可能更明智.例如,我会考虑使用单独的git fetch和git rebase步骤(参见Xavier的答案),并注意到rebase现在--autostash基本上只是你想要的东西,它只是不能通过git pull便利脚本直接获得.1
这就是说,有是一种方法可以做到你问什么.这有点棘手.如果git stash save有一个类似的"强制"选项会更容易git commit --allow-empty,但它没有这样的选择.2 相反,你可以做的是检测是否git stash save推了一个新的藏匿处.如果git stash save退出状态指示是否推送存储,这也会更容易,但同样不会.这意味着我们必须完全依赖不同的技巧.我们从两个事实开始:git rev-parse从"引用"中查找SHA-1,并git stash使用一个特定的引用.
该git rev-parse命令会将任何引用转换为SHA-1:
$ git rev-parse refs/remotes/origin/master
2635c2b8bfc9aec07b7f023d8e3b3d02df715344
Run Code Online (Sandbox Code Playgroud)
引用只是一个名称,通常以refs命名某些SHA-1 ID开头.最常见的是分支:.你可能也使用过标签:,你可能已经使用了远程跟踪分支,比如全名的缩写.refs/heads/branchrefs/tags/tagorigin/masterrefs/remotes/origin/master
该stash脚本使用refs/stash,所以我们可以简单地运行git rev-parse refs/stash.3 我们希望之前运行它git stash save,然后再运行它git stash save.如果输出发生更改,则该git stash save步骤必须将新存储推送到存储堆栈.
我们必须要小心一点,因为如果存储堆栈是空的(因为最后一个存储被先前弹出或删除,或者还没有创建过存储器),git rev-parse则会给出错误消息并且不生成SHA-1:
$ git rev-parse refs/stash
fatal: ambiguous argument 'refs/stash': unknown revision or path not in
the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Run Code Online (Sandbox Code Playgroud)
因此我们实际上需要git rev-parse -q --verify refs/stash,如果引用不存在则默默地产生任何内容,然后我们只需要在任何使用结果的shell脚本中小心一点:
oldsha=$(git rev-parse -q --verify refs/stash)
git stash -q save # add options as desired here
newsha=$(git rev-parse -q --verify refs/stash)
if [ "$oldsha" = "$newsha" ]; then
made_stash_entry=false
else
made_stash_entry=true
fi
... all of your other code goes here ...
if $made_stash_entry; then git stash pop; fi
Run Code Online (Sandbox Code Playgroud)
1该git pull命令基本上是一个简写,git fetch后面跟着git merge,或者,如果你告诉它,运行git fetch后跟通常更合适的命令git rebase.但是,如果将其分解为两个单独的步骤,则可以获得更多控制权,以及在合并或重新定位之前检查传入更改的能力.
2您可以使用较新的有效的强制藏匿创作create和store子命令:创建一个存储,然后存储所产生的SHA-1,你已经被迫即使没有什么藏匿藏匿保存.但并不是每个人都对最新的git有所了解,所以对于脚本来说,依旧的方式可能更明智(或者如前所述,根本不使用藏匿,特别是因为它有各种各样的小但烦人的bug,各种版本git).
3拼出全名是明智的,因为它git rev-parse stash会先找一个名为的分支stash.在编写别名或脚本时,所有引用都是正确的:拼写全名(并--根据需要使用语法)以确保git不会在奇怪的角落情况下执行它认为您的意思.
使用时git stash save <messsage>,您传递的消息将在成功保存后显示。
因此,一个技巧是生成一个时间戳,将其用作消息,如果在结果消息中找到时间戳,则删除最新的存储。
一条线:
t=timestamp-$(date +%s); r=$(git stash save $t); v=$(echo $r|grep $t); if [ "$v" ]; then git stash list; echo "SAVED! NOW REMOVING..."; git stash drop stash@{0}; else echo "Nothing to Stash!"; fi; echo "Stashes: "; git stash list; echo "Done!"
Run Code Online (Sandbox Code Playgroud)
扩展:
# unique timestamp
t=timestamp-$(date +%s)
# stash with message
r=$(git stash save $t)
# check if the value exists
v=$(echo $r|grep $t)
# if the message is found...
if [ "$v" ] then
# DEBUG: Before
git stash list
echo "SAVED! NOW REMOVING..."
# remove last stash
git stash drop stash@{0}
else
echo "Nothing to Stash!"
fi
# DEBUG: after
echo "Stash List: "
git stash list
echo "Done!"
Run Code Online (Sandbox Code Playgroud)
阅读你对为什么要做你所做的事情的解释,我可能会采取完全不同的方法。首先,我会获取您要使用的遥控器:
git fetch <remote> (e.g. git fetch origin)
Run Code Online (Sandbox Code Playgroud)
然后,我将针对该远程的特定分支执行变基:
git rebase <remote>/<branch> (e.g. git rebase origin/master)
Run Code Online (Sandbox Code Playgroud)
这将合并您的更改,并且您仍然能够解决任何冲突。
如果您不喜欢这种方法,您可能需要使用带有--no-commit标志的git pull来代替:
git pull --no-commit
Run Code Online (Sandbox Code Playgroud)
这样合并后就不会执行自动提交。